使用MVVM进行属性更新

时间:2016-04-23 22:39:39

标签: c# wpf mvvm

我已经创建了一个基于MVVM的示例 主窗口XAML:

<Window x:Class="LearnMVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:LearnMVVM"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Window.Resources>
        <ObjectDataProvider x:Key="operationTypeEnum" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:OperationType"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
        <DataTemplate DataType="{x:Type local:SomeUserControlViewModel}">
            <local:SomeUserControl />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="25"/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"/>
            <RowDefinition Height="25"/>
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBox Grid.Column="0" Grid.Row="0" Margin="2" Text="{Binding Path=A, Mode=TwoWay}"/>
        <TextBlock Grid.Column="1" Grid.Row="0" Text="+" TextAlignment="Center" VerticalAlignment="Center" Height="16" Margin="0,4,0,5"/>
        <TextBox Grid.Column="2" Grid.Row="0" Margin="2"  Text="{Binding Path=B, Mode=TwoWay}"/>
        <Button Grid.Column="3" Grid.Row="0" Margin="2" Content="Посчитать" Command="{Binding ClickCommand}"/>
        <TextBox Grid.Column="4" Grid.Row="0" Margin="2" IsReadOnly="True"  Text="{Binding Path=Summa, Mode=TwoWay}"/>

        <ComboBox Grid.Column="2" Grid.Row="1" SelectedItem="{Binding Path=SomeUserControl.Operation, Mode=TwoWay}" ItemsSource="{Binding Source={StaticResource operationTypeEnum}}" />
        <ContentControl Grid.Column="2" Grid.Row="2" BorderThickness="3" BorderBrush="Black" Content="{Binding Path=SomeUserControl}" />
    </Grid>
</Window>

SomeUserControl的XAML:

<UserControl x:Class="LearnMVVM.SomeUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:learnMvvm="clr-namespace:LearnMVVM"
             xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <learnMvvm:SomeUserControlViewModel />
    </UserControl.DataContext>
    <DockPanel>
        <TextBox DockPanel.Dock="Top" Margin="10" Text="{Binding Path=A, Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" />
        <Label DockPanel.Dock="Top" Content="{Binding Path=Operation, diag:PresentationTraceSources.TraceLevel=High}" />
        <TextBox DockPanel.Dock="Top" Margin="10" Text="{Binding Path=B, Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" />
        <Button DockPanel.Dock="Top" Content="=" Margin="20" Command="{Binding CalculateOperationComamnd, Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" />
        <Label DockPanel.Dock="Top" Margin="10" Content="{Binding Path=Result, diag:PresentationTraceSources.TraceLevel=High}" />
    </DockPanel>
</UserControl>

SomeCustomUserControl的ViewModel:

using System;
using System.ComponentModel;
using System.Windows.Input;

namespace LearnMVVM
{
    public enum OperationType
    {
        Sum,
        Sub,
        Div,
        Mul
    }

    public class SomeUserControlViewModel : INotifyPropertyChanged
    {
        public double A { get; set; }
        public double B { get; set; }

        //Команды
        private ICommand calculateOperationCommand;
        public ICommand CalculateOperationComamnd 
        {
            get
            {
                return calculateOperationCommand;
            }
            set
            {
                if (calculateOperationCommand != value)
                {
                    calculateOperationCommand = value;
                    OnPropertyChanged("CalculateOperationComamnd");
                }
            } 
        }

        private OperationType operation;
        public OperationType Operation
        {
            get
            {
                return operation;
            }

            set
            {
                if (operation != value)
                {
                    operation = value;
                    switch (operation)
                    {
                        case OperationType.Sum:
                            CalculateOperationComamnd = new RelayCommand(arg => OperationSum());
                            break;
                        case OperationType.Sub:
                            CalculateOperationComamnd = new RelayCommand(arg => OperationSub());
                            break;
                        case OperationType.Div:
                            CalculateOperationComamnd = new RelayCommand(arg => OperationDiv());
                            break;
                        case OperationType.Mul:
                            CalculateOperationComamnd = new RelayCommand(arg => OperationMul());
                            break;
                    }
                    OnPropertyChanged("Operation");
                }
            }
        }

        private void OperationSum()
        {
            Result = A + B;
        }

        private void OperationSub()
        {
            Result = A - B;
        }

        private void OperationDiv()
        {
            Result = A/B;
        }

        private void OperationMul()
        {
            Result = A*B;
        }

        private double result;
        public double Result
        {
            get { return result; }
            set
            {
                if (Math.Abs(result - value) > 0.0001)
                {
                    result = value;
                    OnPropertyChanged("Result");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}

问题:当我从组合框中更改所选项目并且&#34;计算按钮无效时,自定义控件不会更改。

实际上,SomeCustomControlViewModel中的所有属性都按预期更新,但在主窗口中没有任何效果。

我错过了什么吗?

1 个答案:

答案 0 :(得分:2)

framelayout.post(new Runnable() { @Override public void run() { original = getBitmap(); if (original != null) { //where exception occurs setBitmap(original); } } }); private void setBitmap(Bitmap original) { Bitmap scaledBitmap = scaledBitmap(original, sourceFrame.getWidth(), frameLayout.getHeight()); sourceImageView.setImageBitmap(scaledBitmap); Bitmap tempBitmap = ((BitmapDrawable) frameLayout.getDrawable()).getBitmap(); Map<Integer, PointF> pointFs = getEdgePoints(tempBitmap); polygonView.setPoints(pointFs); polygonView.setVisibility(View.VISIBLE); int padding = (int) getResources().getDimension(R.dimen.scanPadding); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(tempBitmap.getWidth() + 2 * padding, tempBitmap.getHeight() + 2 * padding); layoutParams.gravity = Gravity.CENTER; polygonView.setLayoutParams(layoutParams); } private Bitmap scaledBitmap(Bitmap bitmap, int width, int height) { Matrix m = new Matrix(); //dimensions are always greater than 0 when an image is picked //but still throws exception System.out.println("bitmap height: "+bitmap.getHeight()); System.out.println("bitmap Width: "+bitmap.getWidth()); m.setRectToRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), new RectF(0, 0, width, height), Matrix.ScaleToFit.CENTER); //exception occurs here return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true); } 不是Operation的属性。它是SomeUserControl的视图模型的属性 - 可作为控件SomeUserControl访问。尝试绑定DataContext,如下所示:

ComboBox.SelectedItem

更改是我在路径中添加了SelectedItem="{Binding Path=SomeUserControl.DataContext.Operation, Mode=TwoWay}"

这就是为什么你不使用自定义控件的视图模型,如果你真的想将它们用作控件。您编写一个派生自DataContext的控件类,并为其提供依赖项属性。 Control应该是从Operation派生的类的依赖项属性,而不是viewmodel上的通知属性。然后,您可以通过默认Control应用ControlTemplate来为其定义UI。

你在这里得到的是一个真正的儿童视角模特。使用这种类型的安排,通常父视图模型将提供子视图模型的实例,并将其绑定到子控件本身。然后,任何想要使用子视图模型的属性的人都会绑定Style