如何像代理一样使用Binding?

发布于 2024-12-06 02:01:51 字数 530 浏览 3 评论 0原文

<Setter Property="IsChecked">
    <Setter.Value>
        <MultiBinding>
            <!-- Get value for property -->
            <Binding Path="IsPressed" RelativeSource="{RelativeSource Self}" Mode="OneWay"/>
            <!-- Set value to ViewModel's property -->
            <Binding Path="Shift" Mode="OneWayToSource"/>
        </MultiBinding>
    </Setter.Value>
</Setter>

我需要使用 2 个属性绑定:一个用于获取属性值,另一个用于为 ViewModel 的属性设置值。 我怎样才能实现这个场景?

<Setter Property="IsChecked">
    <Setter.Value>
        <MultiBinding>
            <!-- Get value for property -->
            <Binding Path="IsPressed" RelativeSource="{RelativeSource Self}" Mode="OneWay"/>
            <!-- Set value to ViewModel's property -->
            <Binding Path="Shift" Mode="OneWayToSource"/>
        </MultiBinding>
    </Setter.Value>
</Setter>

I need to use 2 bindings for property: one to get value for property and one to set value to ViewModel's property.
How I can realize this scenario?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

送君千里 2024-12-13 02:01:51

您可以创建几个附加属性。第一个将是您的绑定目标,第二个将包含您的代理的绑定。例子:

然后在 ProxySource OnChange 实现中,您将获得 TextBox 作为 UIElement,在那里您可以从 ProxySource 读取值并将其写入 ProxyTarget。
这不是一个非常干净的方法,但它应该有效。
如果你不能让它工作,我可以稍后写一个完整的示例。
好的,我已经实现了所有内容,这是完整的源代码:

public class ViewModel : ViewModelBase
{
    string sourceText;
    public string SourceText
    {
        get { return sourceText; }
        set
        {
            if (sourceText == value) return;
            sourceText = value;
            System.Diagnostics.Debug.WriteLine("SourceText:" + value);
            RaisePropertyChanged("SourceText");
        }
    }

    string targetText;
    public string TargetText
    {
        get { return targetText; }
        set
        {
            if (targetText == value) return;
            targetText = value;
            System.Diagnostics.Debug.WriteLine("TargetText:" + value);
            RaisePropertyChanged("TargetText");
        }
    }
}

public static class AttachedPropertiesHost
{
    public static object GetProxySource(DependencyObject obj)
    {
        return obj.GetValue(ProxySourceProperty);
    }

    public static void SetProxySource(DependencyObject obj, object value)
    {
        obj.SetValue(ProxySourceProperty, value);
    }

    public static readonly DependencyProperty ProxySourceProperty =
            DependencyProperty.RegisterAttached(
                "ProxySource", typeof(object), typeof(AttachedPropertiesHost),
                new UIPropertyMetadata(null, ProxySourcePropertyPropertyChanged)
            );

    private static void ProxySourcePropertyPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        dependencyObject.Dispatcher.BeginInvoke(
                new { Dp = dependencyObject, NewValue = e.NewValue },
                args => SetProxyTarget(args.Dp, args.NewValue)
            );
    }

    public static object GetProxyTarget(DependencyObject obj)
    {
        return obj.GetValue(ProxyTargetProperty);
    }

    public static void SetProxyTarget(DependencyObject obj, object value)
    {
        obj.SetValue(ProxyTargetProperty, value);
    }

    public static readonly DependencyProperty ProxyTargetProperty =
            DependencyProperty.RegisterAttached("ProxyTarget", typeof(object), typeof(AttachedPropertiesHost));
    }

<TextBox Text="{Binding SourceText, UpdateSourceTrigger=PropertyChanged}" 
             WpfDataGridLayout:AttachedPropertiesHost.ProxySource="{Binding RelativeSource={RelativeSource Self}, Path=Text, UpdateSourceTrigger=PropertyChanged}"
             WpfDataGridLayout:AttachedPropertiesHost.ProxyTarget="{Binding TargetText, Mode=OneWayToSource}"
             />

以及编辑文本框时控制台的输出:
源文本:f
目标文本:f
来源:fh
目标文本:fh
来源文字:fhh
目标文本:fhh

You can create a couple of attached properties. One will be the target of your binding, and second will contain binding for your proxy. Example:

Then in ProxySource OnChange implementation you will get TextBox as UIElement, there you can read value from ProxySource and write it to ProxyTarget.
This is not a very clean aproach, but it should work.
If you can't get it working, I can write a complete sample later.
Ok, I've implemented everything, here's complete source:

public class ViewModel : ViewModelBase
{
    string sourceText;
    public string SourceText
    {
        get { return sourceText; }
        set
        {
            if (sourceText == value) return;
            sourceText = value;
            System.Diagnostics.Debug.WriteLine("SourceText:" + value);
            RaisePropertyChanged("SourceText");
        }
    }

    string targetText;
    public string TargetText
    {
        get { return targetText; }
        set
        {
            if (targetText == value) return;
            targetText = value;
            System.Diagnostics.Debug.WriteLine("TargetText:" + value);
            RaisePropertyChanged("TargetText");
        }
    }
}

public static class AttachedPropertiesHost
{
    public static object GetProxySource(DependencyObject obj)
    {
        return obj.GetValue(ProxySourceProperty);
    }

    public static void SetProxySource(DependencyObject obj, object value)
    {
        obj.SetValue(ProxySourceProperty, value);
    }

    public static readonly DependencyProperty ProxySourceProperty =
            DependencyProperty.RegisterAttached(
                "ProxySource", typeof(object), typeof(AttachedPropertiesHost),
                new UIPropertyMetadata(null, ProxySourcePropertyPropertyChanged)
            );

    private static void ProxySourcePropertyPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        dependencyObject.Dispatcher.BeginInvoke(
                new { Dp = dependencyObject, NewValue = e.NewValue },
                args => SetProxyTarget(args.Dp, args.NewValue)
            );
    }

    public static object GetProxyTarget(DependencyObject obj)
    {
        return obj.GetValue(ProxyTargetProperty);
    }

    public static void SetProxyTarget(DependencyObject obj, object value)
    {
        obj.SetValue(ProxyTargetProperty, value);
    }

    public static readonly DependencyProperty ProxyTargetProperty =
            DependencyProperty.RegisterAttached("ProxyTarget", typeof(object), typeof(AttachedPropertiesHost));
    }

<TextBox Text="{Binding SourceText, UpdateSourceTrigger=PropertyChanged}" 
             WpfDataGridLayout:AttachedPropertiesHost.ProxySource="{Binding RelativeSource={RelativeSource Self}, Path=Text, UpdateSourceTrigger=PropertyChanged}"
             WpfDataGridLayout:AttachedPropertiesHost.ProxyTarget="{Binding TargetText, Mode=OneWayToSource}"
             />

And the output from console while editing textbox:
SourceText:f
TargetText:f
SourceText:fh
TargetText:fh
SourceText:fhh
TargetText:fhh

只是在用心讲痛 2024-12-13 02:01:51

请不要围绕 IsPressed 设计您的解决方案,这实际上是一些人所说的 flash 数据,这意味着它会更快变回默认值 (false)。此外,上下文绑定将具有专用的目标、源和模式。在 MultiBinding 中,不支持以一种方式实现 IsPressed(从源)和另一种方式保存回另一个Target。要进行双向更新,所有绑定都必须是 TowWay

尽管对此的Hack可以使用MultiConverterTarget本身作为值之一。

     <MultiBinding Converter="MyMultiBindingConverter">
          <!-- Get value for property -->
         <Binding Path="IsPressed"
                  RelativeSource="{RelativeSource Self}" Mode="OneWay"/>
          <!-- Set value to ViewModel's property -->
         <Binding BindsDirectlyToSource="True"/>
     </MultiBinding> 

    MyMultiBindingConverter.Convert()
    {
        var myViewModel = values[1] as MyViewModel;
        var isPressed = bool.Parse(values[0].ToString());
        if (isPressed)
        {
            myViewModel.Shift = !myViewModel.Shift;
        }
    }

但强烈推荐这样做。

Please dont design your solution around IsPressed, thats actually what some call a flash data which means it changes back to a default value (false) sooner. Also contextually Binding will have dedicated target, source and mode. In MultiBinding acheiving one way IsPressed (from a Source) and other way saving back to another Target is not supported. For two way update to occur, all bindings have to be TowWay.

Although a Hack to this could be using MultiConverter having a Target itself as one of the values.

     <MultiBinding Converter="MyMultiBindingConverter">
          <!-- Get value for property -->
         <Binding Path="IsPressed"
                  RelativeSource="{RelativeSource Self}" Mode="OneWay"/>
          <!-- Set value to ViewModel's property -->
         <Binding BindsDirectlyToSource="True"/>
     </MultiBinding> 

    MyMultiBindingConverter.Convert()
    {
        var myViewModel = values[1] as MyViewModel;
        var isPressed = bool.Parse(values[0].ToString());
        if (isPressed)
        {
            myViewModel.Shift = !myViewModel.Shift;
        }
    }

But this is strongly NOT recommended.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文