【问题标题】:WPF bind a dynamic generated slider to functionWPF 将动态生成的滑块绑定到功能
【发布时间】:2016-04-07 07:10:09
【问题描述】:

第一:不是Binding Button click to a method的重复——它是关于按钮的,中继命令不能传递我需要的参数

另外,不是 How do you bind a Button Command to a member method? 的重复 - 这是一个没有参数的简单方法 - 与我的问题无关。

显然(但只是为了确保和避免巨魔)不是 Silverlight MVVM: where did my (object sender, RoutedEventArgs e) go? 的重复。

现在解决这个问题(对不起,我真的很讨厌被不理解我的问题的人标记为“重复”),让我们谈谈这个问题::D

我正在尝试将生成的滑块(使用数据模板)绑定到事件(值已更改),我知道无法绑定事件并且我必须使用 ICommand,但我不知道如何获取事件参数到命令函数,这是xaml相关代码:(没有绑定,因为它不起作用)

<Slider Grid.Column="1"  Grid.Row="1" Height="30" IsSnapToTickEnabled="True"  Maximum="100" SmallChange="1" IsMoveToPointEnabled="True"/>

这是我希望它绑定到的函数:

public void vibrationSlider_move(object Sender, RoutedPropertyChangedEventArgs<double> e)
        {
            VibrationValue = (byte)e.NewValue;
            SendPacket(cockpitType, (byte)Index.VibrationSlider, VibrationValue);
        }

如您所见,我需要使用事件附带的“e”,如果不使用“ValueChanged”滑块事件,我不知道如何到达它。

注意事项:

请不要告诉我像这样添加“ValueChanged”属性:

<Slider ValueChanged="VibrationSlider_move"/>

:)

它是使用带有 observableCollection 的 DataTemplate 生成的动态滑块,该函数不在 window.cs 文件中,因此无法仅使用事件。

谢谢。

【问题讨论】:

  • 哦...为什么这么消极。
  • 不是否定的 :) 只是过于谨慎,我会添加一些微笑!

标签: c# wpf


【解决方案1】:

你可以创建一个扩展

public partial class Extensions
{
    public static readonly DependencyProperty ValueChangedCommandProperty = DependencyProperty.RegisterAttached("ValueChangedCommand", typeof(ICommand), typeof(Extensions), new UIPropertyMetadata((s, e) =>
    {
        var element = s as Slider;

        if (element != null)
        {
            element.ValueChanged -= OnSingleValueChanged;

            if (e.NewValue != null)
            {
                element.ValueChanged += OnSingleValueChanged;
            }
        }
    }));

    public static ICommand GetValueChangedCommand(UIElement element)
    {
        return (ICommand)element.GetValue(ValueChangedCommandProperty);
    }

    public static void SetValueChangedCommand(UIElement element, ICommand value)
    {
        element.SetValue(ValueChangedCommandProperty, value);
    }

    private static void OnSingleValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        var element = sender as Slider;
        var command = element.GetValue(ValueChangedCommandProperty) as ICommand;

        if (command != null && command.CanExecute(element))
        {
            command.Execute(element);
            e.Handled = true;
        }
    }
}

然后可以在 xaml 中使用,如下所示。

<Slider Minimum="0" Maximum="100" local:Extensions.ValueChangedCommand="{Binding ValueChangedCommand}"/>

【讨论】:

  • 我创建了一个名为“Extentions”的全新类并复制了该代码,它说“local is an undeclard prefix”关于 xaml 行,知道为什么吗?
  • 因为需要在xaml声明中为扩展添加命名空间。
【解决方案2】:

正如@Philip W 所说,您可以使用例如MVVMLight 帮助处理 MVVM 模式和您手头的问题。

例如,您可以使用 XAMLDataTemplateSlider,如下所示:

<Window x:Class="WpfApplication1.MainWindow"  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:command="http://www.galasoft.ch/mvvmlight"
        mc:Ignorable="d"
        Title="MainWindow" 
        Height="250" 
        Width="250">
    <Window.Resources>
        <DataTemplate x:Key="SomeTemplate">
            <StackPanel Margin="15">
                <!-- Wrong DataContext can drive you mad!1 -->
                <StackPanel.DataContext>
                    <local:SomeTemplateViewModel />
                </StackPanel.DataContext>
                <TextBlock Text="This is some template"/>
                <Slider 
                    Height="30" 
                    IsSnapToTickEnabled="True" 
                    Maximum="100" 
                    SmallChange="1" 
                    IsMoveToPointEnabled="True">
                    <!-- Bind/pass event as command -->
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="ValueChanged">
                            <command:EventToCommand 
                        Command="{Binding Mode=OneWay, Path=ValueChangedCommand}"
                        PassEventArgsToCommand="True" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Slider>
                <!-- Show current value, just for sake of it... -->
                <TextBlock 
                    Text="{Binding Value}"
                    FontWeight="Bold"
                    FontSize="24">
                </TextBlock>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>

    <ContentControl ContentTemplate="{StaticResource SomeTemplate}" />
</Window>

所以基本上你将所需的event 绑定到命名Command 并将EventArgs 作为参数传递给它。然后在您的 ViewModel 中,作为您 Slider 的 DataContext,您处理事件传递为命令。

public class SomeTemplateViewModel : ViewModelBase
{
    private double _value;

    public SomeTemplateViewModel()
    {
        // Create command setting Value as Slider's NewValue
        ValueChangedCommand = new RelayCommand<RoutedPropertyChangedEventArgs<double>>(
            args => Value = args.NewValue);
    }

    public ICommand ValueChangedCommand { get; set; }

    public double Value
    {
        get { return _value; }
        set { _value = value; RaisePropertyChanged(); } // Notify UI
    }
}

这会给你类似的东西。

【讨论】:

  • 嘿 Mikko 感谢您提供超级详细的答案,我很难使用“”标签,我需要安装或使用某种包吗?我不熟悉 MVVMLight 模式
  • 向 XAML 代码添加了缺失的导入。您需要通过 NuGet 包管理器下载 MVVMLight。
  • 我不确定,但我认为您还必须将 System.Windows.Interactivity 添加到您的引用中。而不是添加完整的 MVVMLight NuGet 包,您可以从存储库中复制并粘贴相关的 EventToCommand 类...
  • 令人惊讶的是这有多么复杂,我不明白微软如何不只是实现将函数绑定到事件......
  • 第二次不复杂:)
【解决方案3】:

您可以使用MVVMLight Toolkit,它允许将 EventArgs 作为 CommandParameter 发送到 ViewModel:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="ValueChanged">
        <cmd:EventToCommand Command="{Binding ValueChangedCommand}" PassEventArgsToCommand="True"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

在您的 command.Execute 方法中,您现在获得一个对象作为参数,您只需将其解析为正确的类型...

【讨论】:

    【解决方案4】:

    由于您的滑块是动态生成的,因此没有什么可以阻止您稍后添加 ValueChanged 事件:

    XAML:

    <Slider x:Name="slider" HorizontalAlignment="Left" Margin="10,143,0,0" VerticalAlignment="Top" Width="474" Grid.ColumnSpan="2" />
    

    代码隐藏:

    public MainWindow()
    {
        InitializeComponent();
    
        // it is a good idea to not allow designer to execute custom code
        if (DesignerProperties.GetIsInDesignMode(this))
           return;
    
        slider.ValueChanged += Slider_ValueChanged;
    }
    
    private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        // do your stuff here
    }
    

    正如here 指出的那样,在任何情况下检查design mode 都不简单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-23
      • 1970-01-01
      • 1970-01-01
      • 2013-09-16
      • 1970-01-01
      • 2019-04-18
      • 2016-02-09
      相关资源
      最近更新 更多