首先,我將總結我正在做的事情。然後,我將展示我認爲是展示標題問題的其中一個步驟的相關代碼的相關部分,然後我將在最後解釋問題。對ListView的綁定項目的PropertyChanged爲空(涉及Windows工作流程和ModelItems)
我公開了一個內部庫,用於將我們的一個軟件產品自動化到Windows Workflow,允許工程師(而不是軟件工程師)使用我們的庫,而無需實際編寫代碼。我正在設計一個步驟,用戶將通過該步驟選擇要使用的方法,然後通過工作流程參數填充輸入參數列表。執行工作流將在運行時在對象上調用這個方法(是的,這是有效的)。
我的步驟邏輯
[Designer(typeof(EntityMethodStepDesigner))]
public class EntityMethodStep : CodeActivity
{
...
[Browsable(false)]
public ObservableCollection<ArgumentWrapper> MethodArguments { get; set; }
public EntityMethodStep()
: base()
{
MethodArguments = new ObservableCollection<ArgumentWrapper>();
}
....
protected override void CacheMetadata(CodeActivityMetadata metadata)
{
Collection<RuntimeArgument> arguments = new Collection<RuntimeArgument>();
foreach (ArgumentWrapper wrapper in MethodArguments)
{
RuntimeArgument ra = new RuntimeArgument(wrapper.MethodParameterName, wrapper.Argument.ArgumentType, wrapper.Argument.Direction, true);
metadata.Bind(wrapper.Argument, ra);
arguments.Add(ra);
}
metadata.SetArgumentsCollection(arguments);
}
}
我的步驟視圖
<sap:ActivityDesigner x:Class="MyNamespace.Steps.EntityMethodStepDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
<sap:ActivityDesigner.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</sap:ActivityDesigner.Resources>
<Grid>
<ComboBox Grid.Row="1"
ItemsSource="{Binding AvailableEntityMethods}"
SelectedItem="{Binding SelectedEntityMethod}" />
<GroupBox Grid.Row="3" Header="Parameters">
<ListView ItemsSource="{Binding ModelItem.MethodArguments}"
ItemTemplate="{StaticResource myNonEnumArgumentWrapperTemplate}">
</ListView>
</GroupBox>
</Grid>
myNonEnumArgumentWrapperTemplate數據模板
<DataTemplate x:Key="myNonEnumArgumentWrapperTemplate">
<StackPanel Orientation="Horizontal">
<sapv:ExpressionTextBox Expression="{Binding Path=Argument, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In }"
ExpressionType="{Binding Path=ArgumentType, Converter={StaticResource ModelToObjectValueConverter}, Mode=OneWay }"
OwnerActivity="{Binding ModelItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type sap:ActivityDesigner}}}"
MaxLines="1" />
</StackPanel>
</DataTemplate>
我一步觀點
public partial class EntityMethodStepDesigner : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public EntityMethodStepDesigner()
{
InitializeComponent();
AvailableEntityMethods = new ObservableCollection<MethodInfo>(); // This list is populated elsewhere, so for all intents and purposes consider this list to be populated
this.DataContext = this;
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public ObservableCollection<MethodInfo> AvailableEntityMethods { get; set; }
private MethodInfo _selectedEntityMethod;
public MethodInfo SelectedEntityMethod
{
get { return _selectedEntityMethod; }
set
{
if (_selectedEntityMethod == value) return;
_selectedEntityMethod = value;
if (_selectedEntityMethod != null)
{
ModelProperty methodArguments = ModelItem.Properties["MethodArguments"];
methodArguments.Collection.Clear();
ParameterInfo[] parameters = _selectedEntityMethod.GetParameters();
foreach (ParameterInfo parameter in parameters)
{
ArgumentWrapper wrapper = new ArgumentWrapper(parameter);
methodArguments.Collection.Add(wrapper);
}
}
}
}
}
ArgumentWrapper類
[Serializable]
public class ArgumentWrapper : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ArgumentWrapper()
{
}
public ArgumentWrapper(ParameterInfo methodParameter)
{
// Store the method direction
if (methodParameter.IsIn && methodParameter.IsOut)
MethodParameterDirection = ArgumentDirection.InOut;
else if (methodParameter.IsOut)
MethodParameterDirection = ArgumentDirection.Out;
else
MethodParameterDirection = ArgumentDirection.In;
// Create an argument, with type and direction matching the input
Type activatorType = null;
if (methodParameter.IsIn && methodParameter.IsOut)
activatorType = typeof(InOutArgument<>).MakeGenericType(methodParameter.ParameterType);
else if (methodParameter.IsOut)
activatorType = typeof(OutArgument<>).MakeGenericType(methodParameter.ParameterType);
else
activatorType = typeof(InArgument<>).MakeGenericType(methodParameter.ParameterType);
Argument = (Argument)Activator.CreateInstance(activatorType);
ArgumentType = methodParameter.ParameterType;
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private Argument _argument;
public Argument Argument
{
get { return _argument; }
set
{
if (_argument == value) return;
_argument = value;
OnPropertyChanged("Argument");
}
}
private Type _argumentType;
public Type ArgumentType
{
get { return _argumentType; }
set
{
if (_argumentType == value) return;
_argumentType = value;
OnPropertyChanged("ArgumentType");
}
}
public ArgumentDirection MethodParameterDirection { get; set; }
public void ReferToEntityDirectlyByName(bool enable)
{
if (enable)
{
Argument = new InArgument<string>();
ArgumentType = typeof(string);
}
else
{
Type activatorType;
if (MethodParameterDirection == ArgumentDirection.InOut)
activatorType = typeof(InOutArgument<>).MakeGenericType(MethodParameterType);
else if (MethodParameterDirection == ArgumentDirection.Out)
activatorType = typeof(OutArgument<>).MakeGenericType(MethodParameterType);
else
activatorType = typeof(InArgument<>).MakeGenericType(MethodParameterType);
Argument = (Argument)Activator.CreateInstance(activatorType);
ArgumentType = MethodParameterType;
}
}
}
爲了使這一起,我已經邁出了這一步用的方法的選擇截圖代碼:
這顯示了一個將在一個對象上調用的方法,其中有5個參數,其中3個是枚舉(紅色錯誤是因爲這些字段爲空)。
現在,綁定幾乎可以工作 - 視圖正確初始化,允許我填充字段並執行工作流。但是,如果我更改了參數包裝對象,則視圖不會更新。
問題: 如果我更改了代碼ArgumentWrapper.ArgumentType,更改不會傳播到的ExpressionTextBox。我知道這是因爲當ArgumentToExpressionConverter將輸入的表達式轉換爲參數時,無論類型是否已經更改,它總是返回一個構造類型的參數。我嘗試實施INotifyPropertyChanged,但PropertyChanged爲空,我一直無法解決原因。
我確實想知道是否需要重命名它。 'argumentType'僅用於創建'Argument',一個示例值將是'InArgument'。 'ArgumentType'雖然命名相似,但是用於參數表示的類型,所以在我的示例中它將是'PSMesh'。 –
FluidicTapestry
我也注意到你說要調用'OnPropertyChanged()'。這是我的問題,'PropertyChanged'事件是空的,所以使這個調用什麼都不做。 – FluidicTapestry
哦,這很奇怪......你似乎已經正確地實現了接口。 – Sheridan