ReadOnlyCheckBox 控件模板

发布于 2024-07-23 19:42:39 字数 915 浏览 1 评论 0原文

我一直在尝试创建通用 ReadOnlyCheckBox 样式/模板,但在绑定数据方面遇到问题。 在此处的示例中:

C# WPF 中的只读复选框

直接绑定到 ControlTemplate 定义中的数据,但当然这并不是我真正想要的,因为我希望能够声明新的复选框,如下所示:

        <CheckBox x:Name="uiComboBox" Content="Does not set the backing property, but responds to it."
Style="{StaticResource ReadOnlyCheckBoxStyle}" IsChecked="{Binding MyBoolean}"  Click="uiComboBox_Click"/>

当然,除非我这样做,然后将事件触发器设置为项目符号是 IsChecked 的 TemplateBinding 我完全有我开始的内容! 我想我不明白为什么直接在项目符号中设置绑定与设置 IsChecked 然后绑定到它不同,TemplateBinding 不只是引用正在创建的控件的属性中设置的内容的一种方式吗? 即使数据没有更新,点击如何触发 UI 更新? 是否有“单击我可以覆盖”的触发器来停止更新?

我让所有 DictionaryResource 的东西都工作得很好,所以我对此很满意,为指针欢呼。

我很好奇的另一件事是,是否可以通过在样式中使用 BasedOn 参数来减少我的 Control/Style 模板,那么我只会覆盖我实际需要更改的内容,而不是声明很多我认为的内容无论如何都是标准模板的一部分。 我可能会玩这个。

干杯

编辑

I've been trying to create my generic ReadOnlyCheckBox style/template but I'm having a problem with the binding to the data. In the example here:

A read-only CheckBox in C# WPF

you bind directly to the data from the ControlTemplate definition, but of course this is not really what I want, as I want to be able to declare the new checkbox something like this:

        <CheckBox x:Name="uiComboBox" Content="Does not set the backing property, but responds to it."
Style="{StaticResource ReadOnlyCheckBoxStyle}" IsChecked="{Binding MyBoolean}"  Click="uiComboBox_Click"/>

Except of course when I do this and then set the event trigger on the bullet to be a TemplateBinding of IsChecked I have exactly what I started with! I guess I don't understand why setting the binding directly in the bullet is different from setting IsChecked and then binding to that, isn't the TemplateBinding just a way of referencing what is set in the properties of the control being created? How is the Click triggering the UI update even tho the data does not get updated? Is there a trigger for Click I can override to stop the update?

I got all the DictionaryResource stuff working fine so I am happy with that, cheers for the pointer.

The other thing I was curious about was if it is possible to reduce my Control/Style template by using the BasedOn parameter in the style, then I would only override the things I actually need to change rather than declaring a lot of stuff that I think is part of the standard template anyway. I might have a play with this.

Cheers

ed

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

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

发布评论

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

评论(1

怪我闹别瞎闹 2024-07-30 19:42:39

您遇到的问题是您试图在不应该使用的地方使用 DataBinding。

我不同意您在发布的链接中获得的其他答案。 虽然 ControlTemplate 解决方案看起来整洁有序,但它们并没有解决问题的核心,即您尝试使用单个控件(复选框)来做两件不同的事情:显示状态(例如选中/未选中) )并执行逻辑(远程设备等)。

ControlTemplates 旨在改变控件的显示方式,但不是行为。 你试图改变行为,而不是外表。 请参阅“什么是 ControlTemplate?” 此处了解更多详细信息

为此,您需要存储一些放弃标准绑定并处理一些事件:

XAML:

<Window x:Class="WPFCheckBoxClickTester.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <CheckBox x:Name="foo" Checked="foo_Checked"></CheckBox>
    </Grid>
</Window>

代码隐藏:

using System.ComponentModel;
using System.Threading;
using System.Windows;

namespace WPFCheckBoxClickTester
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private BackgroundWorker _worker = new BackgroundWorker();

        public Window1()
        {
            InitializeComponent();

            foo.IsThreeState = false;
            this._worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
            this._worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
        }

        private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            foo.IsChecked = true;
            foo.IsEnabled = true;
            return;
        }

        private void _worker_DoWork(object sender, DoWorkEventArgs e)
        {
            Thread.Sleep(500);
            return;
        }

        private void foo_Checked(object sender, RoutedEventArgs e)
        {
            if( foo.IsChecked == true && this.foo.IsEnabled )
            {
                this.foo.IsChecked = false;
                this.foo.IsEnabled = false;

                this._worker.RunWorkerAsync();
            }
            return;
        }

    }
}

上面的代码示例使您能够通过BackgroundWorker异步执行一些代码——我已经放入了Thread.Sleep作为占位符。 我还使用 foo.IsEnabled 作为 foo_Checked 中的哨兵值,但您可能需要一些额外的状态来处理所有情况(例如,从“已检查”到“未检查”)。

The problem you're running into is that you're trying to use DataBinding where you shouldn't.

I disagree with other answers you've been getting in the link you've posted. While the ControlTemplate solutions appear neat and tidy, they don't get at the heart of your problem, which is, you're trying to use a single control (a CheckBox) to do two different things: show state (e.g. checked/unchecked) and perform logic (remote device, etc.).

ControlTemplates are designed to change the way a control appears, but not behaves. You're trying to change behavior, not appearance. See "What Is a ControlTemplate?" here for more details

To do that, you're going to have to store some forego the standard binding and handle some events:

XAML:

<Window x:Class="WPFCheckBoxClickTester.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <CheckBox x:Name="foo" Checked="foo_Checked"></CheckBox>
    </Grid>
</Window>

Code-Behind:

using System.ComponentModel;
using System.Threading;
using System.Windows;

namespace WPFCheckBoxClickTester
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private BackgroundWorker _worker = new BackgroundWorker();

        public Window1()
        {
            InitializeComponent();

            foo.IsThreeState = false;
            this._worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
            this._worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
        }

        private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            foo.IsChecked = true;
            foo.IsEnabled = true;
            return;
        }

        private void _worker_DoWork(object sender, DoWorkEventArgs e)
        {
            Thread.Sleep(500);
            return;
        }

        private void foo_Checked(object sender, RoutedEventArgs e)
        {
            if( foo.IsChecked == true && this.foo.IsEnabled )
            {
                this.foo.IsChecked = false;
                this.foo.IsEnabled = false;

                this._worker.RunWorkerAsync();
            }
            return;
        }

    }
}

The above code example gives you the ability to execute some code async via BackgroundWorker -- I've put in a Thread.Sleep as a placeholder. I'm also using foo.IsEnabled as a sentinel value in foo_Checked, but you may need some extra state here to handle all of your cases (for instance, going from Checked to Unchecked).

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