将命令/参数传递给BackCode?

时间:2018-05-13 13:25:46

标签: c# wpf mvvm parameters

自学并挣扎于可能是一个基本概念。所以任何额外的解释都是受欢迎的......我有以下代码,它们完美地适用于Button_Click事件和Code Behind。我可以使用一个小代码,因为它基本上只是操纵视图。但是,我想从ViewModel获取数据/业务逻辑。我能够确认(使用messagebox.show)我的数据正确传递,但是UI不会像使用来自Button_Click事件的数据那样使用新数据进行更新。我已经有一段时间困难了,并继续寻找工作。据我所知,我的方法完全错了。我真的很想知道如何做到这一点。

WPF

<StackPanel Grid.Row="1"  VerticalAlignment="Bottom">

        <TextBox x:Name="NumberOfDays" HorizontalAlignment="Left" Background="GreenYellow" Foreground="Black">

        </TextBox>
        <StackPanel Orientation="Horizontal">
            <Button Content="change hello row" Click="Button_Click" HorizontalAlignment="Left" Background="GreenYellow" Foreground="Black">

            </Button>

            <Button  Content="TestCommand5" Margin="0 0 0 0" Padding="5" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="16"
                     CommandParameter="{Binding objActiveJobClass.JobID}"
                     Command="{Binding TestCommand5}" 
                     IsTabStop = "False" FocusVisualStyle="{DynamicResource MyFocusVisual}"
                     Style="{Binding Mode=OneWay, Source={StaticResource NavigationButtonStyle}}">

            </Button>
        </StackPanel>


        <Label Content="Gant Chart Area" HorizontalAlignment="Left"/>

        <ScrollViewer Width="1200"  HorizontalAlignment="Left" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
            <Grid >
                <Canvas x:Name="GantChartCanvas" HorizontalAlignment="Left" Background="Yellow" Height="405" />
            </Grid>

        </ScrollViewer>

    </StackPanel>

BackCode:

public partial class GantChartUserControl : UserControl
{
    public GantChartUserControl()
    {
        InitializeComponent();
    }

    public GantChartUserControl(int Duration)
    {
        InitializeComponent();
        CreateTimeLine(Duration);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        int variable = 0;
        if (NumberOfDays != null)
        {
            int.TryParse(NumberOfDays.Text, out variable);
            if (variable > 0)
            {
                CreateTimeLine(variable);
            }
            else
            {
                MessageBox.Show($"\"{NumberOfDays.Text}\" is not an INTEGER greater than Zero.");
            }
        }
    }

    public void CreateTimeLine(int duration)
    {
        MessageBox.Show($"CreateTimeLine duration {duration}");

        GantChartCanvas.Children.Clear();

        double ControlWidth = 100d;
        int Duration = duration;

        for (int i = 0; i < Duration; i++)
        {
            Label u1 = new Label();
            u1.HorizontalAlignment = HorizontalAlignment.Left;
            u1.VerticalAlignment = VerticalAlignment.Bottom;
            u1.HorizontalContentAlignment = HorizontalAlignment.Center;
            u1.VerticalContentAlignment = VerticalAlignment.Center;
            u1.Background = IsOdd(i) ? Brushes.Gray : Brushes.DarkGray;

            u1.Height = 30;
            u1.Width = ControlWidth;

            u1.SetValue(Canvas.LeftProperty, (ControlWidth * i));
            u1.SetValue(Canvas.BottomProperty, 0d);
            u1.Content = string.Concat("LABEL ", i + 1);

            GantChartCanvas.Width = Duration * ControlWidth;
            GantChartCanvas.Children.Add(u1);
        }         
    }

    public static bool IsOdd(int value)
    {
        return value % 2 != 0;
    }       
}

视图模型

private ICommand _TestCommand5;
    public ICommand TestCommand5
    {
        get
        {
            if (_TestCommand5 == null)
            {
                _TestCommand5 = new RelayCommand<object>(ExecuteTestCommand5, CanExecuteTestCommand5);
            }

            return _TestCommand5;
        }
    }
    public bool CanExecuteTestCommand5(object parameter)
    {
        return true;
    }
    public void ExecuteTestCommand5(object parameter)
    {
        Debug.WriteLine($"\nDataBaseHelperClass: {System.Reflection.MethodBase.GetCurrentMethod()}");

        int testint = 44;
        GantChartUserControl objGantChartUserControl = new GantChartUserControl();
        objGantChartUserControl.CreateTimeLine(testint);
    }

2 个答案:

答案 0 :(得分:0)

您可以使用MVVMLight框架,它可以简化您的绑定。 使用此框架,您只需创建属性public RelayCommand YourButton{ get; set; }

即可

在ViewModel的构造函数中,您只需添加此行 YourButton = new RelayCommand(Method); // Method is the method to call when you click on the button

之后,您只需要绑定属性上的按钮。

一个小例子:

视图模型:

    public RelayCommand MyButton { get; set; }


    public MainViewModel()
    {
        MyButton = new RelayCommand(Action);
    }

    public void Action(){
        Console.Writeline("Button Pressed");
    }

WPF

<Button Command="{Binding MyButton}" Content="Button"/>

当你使用绑定时,它会更加美观,以最大限度地减少你的代码。

答案 1 :(得分:-1)

在您的视图(xaml)中,首先将VM设置为DataContext。有办法做到这一点,但我只会告诉你一个:

<UserControl x:Class="MyApp.GantChartUserControl"
             ...
             xmlns:local="clr-namespace:MyApp"> <!--adjust the location(namespace.folder) of your VM as you like-->
   <UserControl.DataContext>
      <local:GantChartUserControlViewModel/> <!--this sets the GantChartUserControlVM as DataContext-->
   </UserControl.DataContext>
...

View(UserControl)不应该打扰任何数据操作,而只是显示(绑定)ViewModel的属性,该属性是专门公开的。我真的建议把所有这些代码都写在ViewModel中。那么,你想要在Code Behind(xaml.cs)中拥有的是:

public partial class GantChartUserControl : UserControl
{
    public GantChartUserControl()
    {
        InitializeComponent();
    }
}

ViewModel:

public class GantChartUserControlViewModel : INotifyPropertyChanged
{
   // boiler-plate
   public event PropertyChangedEventHandler PropertyChanged;
   protected virtual void OnPropertyChanged(string propertyName)
   {
       PropertyChangedEventHandler handler = PropertyChanged;
       if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
   }

   // Property you want to expose:
   public ObservableCollection<int> MyIntegers
   {
       get {return _myIntegers;}
       set { _myIntegers = value; OnPropertyChanged("MyIntegers"); }
   }
   private ObservableCollection<int> _myIntegers;

   // ICommand
   public ICommand TestCommand5 { get; private set;}

   // constructor
   public GantChartUserControlViewModel()
   {
       MyInteger = new ObservableCollection<int>();
       new RelayCommand<object>(ExecuteTestCommand5, CanExecuteTestCommand5);
   }

    public bool CanExecuteTestCommand5(object parameter)
    {
        return true;
    }
    public void ExecuteTestCommand5(object parameter)
    {
        Debug.WriteLine($"\nDataBaseHelperClass: {System.Reflection.MethodBase.GetCurrentMethod()}");
        int testint = (int)parameter;
        CreateTimeLine(testint);
    }

    private void CreateTimeLine(int duration)
    {
        MyIntegers.Clear();
        for(int i=0;i<duration;i++)
        {
            MyIntegers.Add(i);
        }
    }      
}

现在您已准备好VM,我们需要将其绑定回View。所以,回到你的xaml,而不是使用Canvas,我建议使用ItemsControl(或ListView)

<ScrollViewer>
    <ItemsControl ItemsSource={Binding MyIntegers, Mode=OneWay}>
        <!--we have the integer collection, but View has the responsibility to set the layout, etc. which I usually call it the datatemplate-->
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Label HorizontalAlignment="Left"
                       VerticalAlignment="Bottom"
                       HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center"    
                       Height="30"
                       Width="100">
                     <Label.Background>
                         <Binding>
                             <!--Why empty binding? it just means we are binding to the single int from the ItemsSource-->
                             <Binding.Converter>
                                 <!--What is this converter? We'll get there later-->
                                 <converter: IsOddToColorConverter/>
                             </Binding.Converter>
                         </Binding>
                     </Label.Background>
                 </Label>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <!-- I see that you wanted to have the labels put in horizontal, so we need to change the itemspanel from the default (vertical)-->
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
                <!-- you could use WrapPanel, in case if you want it to wrap, if it does not fit horizontally-->
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</ScrollViewer>

因此,上面的转换器是将绑定整数转换为背景颜色的工具。您需要在不同的类中创建转换器:

/// <summary>This convert number to brush</summary>
public class IsOddToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo language)
    {
        // value is the integer input, we don't care about parameter or language
        // output should be type of Brush
        if (value is int && targetType == typeof(Brush))
        {
            bool isOdd = ((int)value) % 2 != 0;
            return isOdd ? Brushes.Gray : Brushes.DarkGray;
        }
        // if input (and output) is unknown
        return Brushes.Transparent;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo language)
    {
        // We don't care about this
        throw new NotSupportedException();
    }
}

那么,我们如何使用这个转换器呢?再次回到您的视图(xaml)。在UserControl级别,请指定路径

 xmlns:converter="clr-namespace:MyApp.Converters" <!--if your converter you defined earlier is inside Converters folder-->
<!--since calling it as converter: IsoddToColorConverter will create a new instance. It might be better to declare this as a static resource, so memory usage won't grow, even if you are using it multiple times. For how to do it, please look in the internet-->

然后,瞧,这应该符合MVVM模式,您的代码更清晰,更易于维护。

请注意,这是您需要做的基本概念。最终你会发现一些框架(PrismMVVMLight等),它们可以帮助你减少需要编写的代码数量。并且,我真的建议你更早地开始学习MVVM。使用旧Forms样式(大量代码隐藏)编写WPF并不能充分利用WPF的优势。