簡體   English   中英

在WPF應用程序中使用MVVM / MVVMLight時如何與UI元素進行交互

[英]How to interact with UI elements when using MVVM/MVVMLight in a WPF app

根據我下面的代碼,我希望能夠在單擊Button 1時更改Button 2的背景顏色。

XAML文件

    <Grid>
        <Button x:Name="Button1" 
                Content="Button 1" 
                Command="{Binding Button1Command}"/>

        <Button x:Name="Button2" 
                Content="Button 2"/>
    </Grid>

ViewModel文件

public class MyViewModel : ViewModelBase
{
    public ICommand Button1Command{get;private set;}

    public MyViewModel(){
        Button1Command = new RelayCommand(() => button1_Click());
    }

    private void button1_Click()
    {
        Console.WriteLine("Button 1 clicked");

        // how can I change the background color of Button 2 here
        this.Dispatcher.Invoke(() => {
           Button2.Background = Brushes.Red;
        });
    }
}

除了pm_2提到的內容之外,您還可以利用MVVMLight的Messenger類。 VM可以發送視圖接收的消息以更改背景。

public class ChangeBackgroundMessage
{
    public Brush TheColor { get; set; } 
} 

然后在你的VM中:

Button1Command = new RelayCommand(() => ExecuteButtonCommand());

....

private void ExecuteButtonCommand()
{
    Messenger.Default.Send<ChangeBackgroundMessage>(new ChangeBackgroundMessage { TheColor = Brushes.Red } );
} 

並在您的視圖中:

public partial class MyView : UserControl
{
    public MyView()
    {
         InitializeComponent();
         Messenger.Default.Register<ChangeBackgroundMessage>(this, m => ReceiveChangeBackgroundMessage(m);
    } 

    private void ReceiveChangeBackgroundMessage(ChangeBackgroundMessage m)
    {
          // If you need to ensure this executes only on UI thread, use the
          // DispatcherHelper class

          DispatcherHelper.CheckBeginInvokeOnUI(() => button2.Background = m.TheColor);
    }

}

另一種選擇是擁有View查看其ViewModel的“視圖服務”。 例如:

public interface IMySpecificViewService
{ 
    void ChangeButtonColor(Brush color);
} 

在VM中:

public IMySpecificViewService ViewService { get; set; } 

並在視圖中

public partial class MyView : UserControl, IMySpecificViewService
...
public MyView()
{ 
    var vm = (MyViewModel)this.DataContext;
    vm.ViewService = (IMySpecificViewService)this;
} 

public void ChangeButtonColor(Brush color)
{
    Button2.Background = color;
}  

可以在VM的命令處理程序中調用它:

private void ExecuteButtonCommand()
{
    ViewService?.ChangeButtonColor(Brushes.Red);
} 

當我無法直接綁定到VM中的屬性時,我發現我使用這些方法(或者我不想在VM中放出任何View特定的東西),並且我需要對操作控件進行更精細的控制。

我想到了兩種方法 - 第一種方法是簡單地將Button2的背景顏色綁定到viewmodel上的屬性。 您可以將它作為畫筆從視圖模型中公開; 雖然與MVVM更一致的方式是創建一個值轉換器。

想法是Button2的背景,盡管與Button1相關聯,實際上是與按下Button1時已經改變的狀態相關聯; 然后,值轉換器將狀態(ViewModel的域)映射為顏色(視圖的域)。

這樣做意味着你可以在button1的視圖模型命令中更改狀態,但不必涉及button1_click事件,因為它現在是不必要的。

這個問題說明了如何實現這一目標。

首先,您需要在視圖模型中聲明一個控制背景顏色的屬性,以及一個按鈕可以調用以切換它的命令處理程序。 這可能看起來有點冗長,但您很快就會習慣使用MVVM,並且有一些框架可以用來最小化它,如果它真的困擾你。 所以這是主視圖模型:

public class MainViewModel : ViewModelBase
{
    #region Background Color Flag

    private bool _Flag;
    public bool Flag
    {
        get { return this._Flag; }
        set
        {
            if (this._Flag != value)
            {
                this._Flag = value;
                RaisePropertyChanged(() => this.Flag);
            }
        }
    }

    #endregion Background Color Flag

    #region Button Command Handler

    private ICommand _ButtonCommand;
    public ICommand ButtonCommand
    {
        get { return this._ButtonCommand = (this._ButtonCommand ?? new RelayCommand(OnButtonPressed)); }
    }

    private void OnButtonPressed()
    {
        this.Flag = !this.Flag;
    }

    #endregion Button Command Handler

    public MainViewModel()
    {
    }

}

MVVM的目標之一是盡可能在視圖和視圖模型之間進行松散耦合。 Button的命令綁定應該相當簡單,但要設置第二個按鈕的背景,您可以使用DataTriggers:

<StackPanel Orientation="Vertical">

    <Button Content="Toggle Background" HorizontalAlignment="Left" VerticalAlignment="Top"
        Command="{Binding ButtonCommand}" />

    <Button Content="Hello World!" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Button.Style>
            <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Flag}" Value="False">
                        <Setter Property="Background" Value="Red" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Flag}" Value="True">
                        <Setter Property="Background" Value="Green" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>

</StackPanel>

當您單擊第一個按鈕時,這將導致第二個按鈕的背景在紅色和綠色之間切換:

在此輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM