我想将字典绑定到按钮的CommandParameter。 这是我的xaml代码:
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MyMultiValueConverter}">
<Binding>
<Binding.Source>
<system:String>SomeString</system:String>
</Binding.Source>
</Binding>
<Binding>
<Binding.Source>
<models:StringObjectPair Key="UserId" Value="{Binding User.Id, UpdateSourceTrigger=PropertyChanged}" />
</Binding.Source>
</Binding>
<Binding>
<Binding.Source>
<models:StringObjectPair Key="UserName" Value="{Binding User.Name, UpdateSourceTrigger=PropertyChanged}" />
</Binding.Source>
</Binding>
</MultiBinding>
</Button.CommandParameter>
StringObjectPair类:
public class StringObjectPair : FrameworkElement
{
public string Key { get; set; }
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(StringObjectPair), new PropertyMetadata(defaultValue: null));
public object Value
{
get { return GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
}
在MyMultiValueConverter中输入值[1] .Value和values [2] .Value属性我看到空值,但User.Id和User.Name不等于null。 在输出窗口中没有错误。 我怎么绑这个?
答案 0 :(得分:0)
我找到了解决方案
StringObjectPair类的变化:
public class StringObjectPair
{
public string Key { get; set; }
public object Value { get; set; }
}
XAML的变化:
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MyMultiValueConverter}">
<Binding /><!--This is DataContext-->
<Binding>
<Binding.Source>
<system:String>SomeString</system:String>
</Binding.Source>
</Binding>
<Binding>
<Binding.Source>
<!--Just string in Value-->
<models:StringObjectPair Key="UserId" Value="User.Id" />
</Binding.Source>
</Binding>
<Binding>
<Binding.Source>
<models:StringObjectPair Key="UserName" Value="User.Name" />
</Binding.Source>
</Binding>
</MultiBinding>
</Button.CommandParameter>
在MyMultiValueConverter中,我只是根据值得到属性:
var dataContext = values[0];
var someString = values[1] as string;
var parameters = new Dictionary<string, object>();
for (var i = 2; i < values.Length; i++)
{
var pair = values[i] as StringObjectPair;
if (!string.IsNullOrEmpty(pair?.Key) && !parameters.ContainsKey(pair.Key))
{
var props = (pair.Value as string)?.Split('.') ?? Enumerable.Empty<string>();
var value = props.Aggregate(dataContext, (current, prop) => current?.GetType().GetProperty(prop)?.GetValue(current, null));
parameters.Add(pair.Key, value);
}
}
答案 1 :(得分:0)
首先,对于这种情况,使用将逻辑从转换器移动到视图模型要容易得多。应该可以从viewmodel访问该命令的所有输入。那么你根本不需要命令参数:
public class MainWindowViewModel
{
private User _user;
public MainWindowViewModel()
{
MyCommand = new DelegateCommand(() =>
{
//Here you can access to User.Id, User.Name or anything from here
});
}
public DelegateCommand MyCommand { get; private set; }
public User User
{
get { return _user; }
set
{
if (value == _user) return;
_user = value;
OnPropertyChanged();
}
}
}
其次,你原来绑定到User.Id没有用,因为你创建的StringObjectPairs不在VisualTree中,因此没有从父级继承的datacontext。但是,为什么不简化多重绑定:
<MultiBinding Converter="{StaticResource MyMultiValueConverter}">
<Binding Source="SomeString" />
<Binding Path="User.Id" />
<Binding Path="User.Name" />
</MultiBinding>
var someString = (string)values[0];
var userId = (int)(values[1] ?? 0);
var userName = (string)values[2];
我可以想象使用没有多重绑定的更简单的解决方案:
<Button Command="..."
CommandParameter="{Binding User, Converter={StaticResource MyConverter},
ConverterParameter=SomeString}" />
public class MyConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var user = (User)value;
var someString = (string)paramenter;
int userId = user.Id;
string userName = user.Name;
return ...
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
修改强>: 如果你坚持将键值对传递给命令(虽然我不认为它是一个好习惯)你可以像这样简化xaml:
<MultiBinding Converter="{StaticResource MyMultiValueConverter}">
<Binding Source="SomeString" ConverterParameter="SomeString" Converter="{StaticResource KeyValueConverter}" />
<Binding Path="User.Id" ConverterParameter="Id" Converter="{StaticResource KeyValueConverter}"/>
<Binding Path="User.Name" ConverterParameter="Name" Converter="{StaticResource KeyValueConverter}"/>
</MultiBinding>
public class KeyValueConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new KeyValuePair<string, object>((string)parameter, value);
}
}
public class DictionaryMultiConverter : IMultiValueConverter
{
public object Convert(object[] keyValues, Type targetType, object parameter, CultureInfo culture)
{
return keyValues.Cast<KeyValuePair<string, object>>()
.ToDictionary(i => i.Key, i => i.Value);
}
}