繁体   English   中英

WPF:绑定命令参数MultiBinding中的自定义依赖项属性

[英]WPF: Binding custom dependency property in command parameter MultiBinding

我想将字典绑定到按钮的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中,将values [1] .Value和values [2] .Value属性放入空值,但User.Id和User.Name不等于空值。 在输出窗口中没有错误。 我该如何绑定呢?

我找到了解决方案

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);
    }
}

首先,对于这种情况,使用逻辑从转换器到视图模型的转换要容易得多。 该命令的所有输入都应该可以从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绑定无效,因为创建的StringObjectPair不在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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM