将DependencyProperty的值设置为ViewModel属性

时间:2017-09-14 20:03:27

标签: c# wpf xaml mvvm

不确定我想要的是否可能,但我也不知道为什么不是。

我有一个带有依赖项属性(string)的用户控件,我在XAML中定义了该属性,例如如下:

<Window ... (EngraveUnitWindow)
    DataContext = EngraveUnitViewModel
    ...
    ...

    <parameters:DoubleParameterUserControl 
        DisplayName="Exchanger Offset [deg]" 
        DataContext="{Binding ExchangerOffset}"/>

视图模型&#39; EngraveUnitViewModel&#39; :

public class EngraveUnitViewModel : ViewModelBase, IUnitViewModel
    ...
    ...
    public DoubleParameterViewModel ExchangerOffset { get; }

我想要实现的目标是在DisplayName中将ParameterName的值设置为DoubleParameterViewModel属性。所以我创建了一个Style,它将DisplayName绑定到viewmodel,如下所示:

<UserControl.Resources>
    <Style TargetType="parameters:DoubleParameterUserControl">
        <Setter Property="DisplayName" Value="{Binding ParameterName, Mode=OneWayToSource}"/>
    </Style>
</UserControl.Resources>

以下完整的DoubleParameterUserControl代码:

<UserControl 
    ...
    ...
    d:DataContext="{d:DesignInstance viewModels:DoubleParameterViewModel, d:IsDesignTimeCreatable=False}"
             Margin="5">

    <UserControl.Resources>
        <Style TargetType="parameters:DoubleParameterUserControl">
            <Setter Property="DisplayName" Value="{Binding ParameterName, Mode=OneWayToSource}"/>
        </Style>
    </UserControl.Resources>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0" Text="{Binding ElementName=DoubleParameter, Path=DisplayName}" VerticalAlignment="Center" Margin="5,0,0,0" />

        <Border Grid.Column="1" BorderThickness="1" BorderBrush="LightGray" Margin="0, 0, 5, 0">
            <TextBlock 
                VerticalAlignment="Center"
                Text="{Binding Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" 
                Margin="5, 0, 5, 0">
                <TextBlock.InputBindings>
                    <MouseBinding Gesture="LeftClick" Command="{Binding ShowNumpadCommand}" />
                </TextBlock.InputBindings>
            </TextBlock>

        </Border>
        <Button x:Name="_button" Grid.Column="2" MinWidth="30" MinHeight="30" Content="..." Command="{Binding ShowNumpadCommand}"/>
    </Grid>
</UserControl>

它的代码背后(我定义了DependencyProp:

public partial class DoubleParameterUserControl
{
    public string DisplayName
    {
        get => (string)GetValue(DisplayNameProperty);
        set => SetValue(DisplayNameProperty, value);
    }

    public static readonly DependencyProperty DisplayNameProperty =
        DependencyProperty.Register(nameof(DisplayName), typeof(string), typeof(DoubleParameterUserControl),
            new PropertyMetadata(""));

    public DoubleParameterUserControl()
    {
        InitializeComponent();

        _button.Focus();
    }
}

为了完整性,viewmodel:

public class DoubleParameterViewModel : ViewModelBase
{
    private readonly Parameter<double> parameter;
    private double value;

    public RelayCommand ShowNumpadCommand { get; }

    public string ParameterName { get; set; }

    public double Value
    {
        get => parameter.Value;
        set
        {
            parameter.Value = value;
            Set(() => Value, ref this.value, value);
        } 
    }

    public DoubleParameterViewModel(Parameter<double> parameter)
    {
        this.parameter = parameter;

        ShowNumpadCommand = new RelayCommand(ShowNumpad);
    }

    private void ShowNumpad()
    {
        var numpadViewModel = new VirtualKeypadsViewModel(true)
        {
            ParameterName = ParameterName,
            Input = Value.ToString("F2", CultureInfo.InvariantCulture)
        };

        var numpad = new Numpad
        {
            Owner = System.Windows.Application.Current.MainWindow,
            DataContext = numpadViewModel
        };

        if (numpad.ShowDialog() == true)
        {
            Value = numpadViewModel.ResultAsDouble();
        }
    }
}

为了清楚起见,ViewModel中的属性ParameterName永远不会被设置。所以在我的代码中,我想弹出一个Numpad对话框,它在标题栏中显示参数名称,但是ParameterName没有收到绑定的DisplayName。

我希望有人能解释我如何解决这个问题。 (或者,这是不可能的,如果不幸的话,为什么不这样)

1 个答案:

答案 0 :(得分:2)

似乎DoubleParameterViewModel.ParameterName仅用于在执行ShowNumpadCommand时提供名称。如果是这种情况,请忘记该属性,只需将DisplayName作为命令参数传递。

public ICommand ShowNumpadCommand { get; }

public DoubleParameterViewModel(Parameter<double> parameter)
{
    this.parameter = parameter;
    ShowNumpadCommand = new RelayCommand<string>(ShowNumpad);
}

private void ShowNumpad(string parameterName)
{
    /* ... */
}

摆脱Style,并将按钮的命令参数绑定到其所有者的DisplayName

<UserControl x:Name="EditorRoot">
  <!-- ... -->
  <Button x:Name="_button"
          Command="{Binding ShowNumpadCommand}"
          CommandParameter="{Binding ElementName=EditorRoot, Path=DisplayName}" />
  <!-- ... -->
</UserControl>