【问题标题】:WPF How correct modify view from ICommand with MVVMWPF 如何使用 MVVM 从 ICommand 正确修改视图
【发布时间】:2019-02-22 00:15:40
【问题描述】:

我需要在控件展开之前加载 ComboBox ItemsSource。如果加载失败,我想将边框画笔颜色设置为红色并显示错误提示。我可以在ICommand.Execute 方法中执行此操作,还是应该使用ValidationRule 之类的方法?

代码:

class ViewModel : INotifyPropertyChanged
{
    public string Server { get {...} set {...} }
    public ObservableCollection<string> ServerCollection { get; }

    public ICommand LoadServerListCommand { get; }

    protected ConnectionViewModel()
    {
        ServerCollection = new ObservableCollection<string>();
        LoadServerListCommand = new DelegateCommand( LoadServerList );
    }

    private void LoadServerList( object param )
    {
        var comboBox = param as ComboBox;
        if ( comboBox != null && !comboBox.IsDropDownOpen )
        {
            try
            {
                ServerCollection.Clear();
                ///... Load();

                comboBox.BorderBrush = //default;
                comboBox.ToolTip = null;
            }
            catch( InvalidOperationException ex )
            {
                comboBox.BorderBrush = //red;
                comboBox.ToolTip = new ToolTip()
                {
                    Content = ex.Message
                };
            }
        }
    }
}

XAML:

<ComboBox x:Name="cbServer" ItemsSource="{Binding ServerCollection}" 
          SelectedItem="{Binding Server, Mode=TwoWay}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PreviewMouseDown">
            <i:InvokeCommandAction Command="{Binding Path=LoadServerListCommand}" 
                                   CommandParameter="{Binding ElementName=cbServer}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>

【问题讨论】:

  • 你不应该从你的 ViewModel 修改你的视图,视图应该改变自己!深入了解我认为可以帮助您的 DataBinding

标签: c# wpf xaml mvvm


【解决方案1】:

您可以在视图模型中添加一个属性来指示加载是否成功并绑定到该属性,并在视图中使用 Style 和 DataTrigger 更改 ComboBox 的相应属性。

设置ComboBoxBorderBrush 需要您为其ToggleButton 定义自定义模板:https://blog.magnusmontin.net/2014/04/30/changing-the-background-colour-of-a-combobox-in-wpf-on-windows-8/

ComboBox 包装在Border 元素中会更容易:

<Border BorderThickness="1">
    <ComboBox x:Name="cbServer" ItemsSource="{Binding ServerCollection}"
                  SelectedItem="{Binding Server, Mode=TwoWay}">
        <ComboBox.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.WindowFrameBrushKey}" Color="Red"/>
        </ComboBox.Resources>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Loaded">
                <i:InvokeCommandAction Command="{Binding Path=LoadServerListCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <ComboBox.Style>
            <Style TargetType="ComboBox">
                <Setter Property="ToolTip" Value="{Binding Error}" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Error.Length, FallbackValue=0}" Value="0">
                        <Setter Property="ToolTip" Value="{x:Null}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ComboBox.Style>
    </ComboBox>
    <Border.Style>
        <Style TargetType="Border">
            <Setter Property="BorderBrush" Value="Red" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Error.Length, FallbackValue=0}" Value="0">
                    <Setter Property="BorderBrush" Value="{x:Null}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Border.Style>
</Border>

查看模型:

private void LoadServerList(object parameter)
{
    try
    {
        //throw new InvalidOperationException("test");
        ServerCollection.Clear();
        ///... Load();
        Error = string.Empty;
    }
    catch (InvalidOperationException ex)
    {
        Error = ex.Message;
    }
}

private string _error;
public string Error
{
    get { return _error; }
    set { _error = value; NotifyPropertyChanged(); }
}


public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    • 1970-01-01
    • 2013-10-02
    • 1970-01-01
    相关资源
    最近更新 更多