【问题标题】:WPF VB.NET - Reference Controls in MainWindow from a ModuleWPF VB.NET - 模块中 MainWindow 中的引用控件
【发布时间】:2013-04-30 11:53:09
【问题描述】:

我想在我的第一个 WPF 应用程序中使用模块,因为我习惯于在我之前创建的 WinForm 应用程序中使用它们。所以我有这个按钮,里面有一个文本块。

MainWindow.xaml:

<Button x:Name="Connection_Button" Width="200" Height="30" Margin="5,5,5,5">
                        <TextBlock FontSize="14" MouseDown="TextBlock_MouseDown">CONNECT</TextBlock>
                    </Button>

在 WinForms 之前,我可以通过添加 MainForm 轻松引用按钮及其文本属性。在控件之前,但是我如何通过模块在 WPF 中执行此操作,类似于下面?我什至如何在模块代码的顶部声明控件?以及 TextBlock 等控件内的元素?

Module_Connection.vb 以我的旧 WinForm 方式:

Private Sub Connect()
        If MainForm.Connection_Button.Text = "Connect" Then
        ' Code

【问题讨论】:

    标签: wpf vb.net reference module wpf-controls


    【解决方案1】:

    您通常不会在 WPF 中执行此操作。

    将应用程序逻辑基于 UI 元素的状态并不是一个好主意。

    为什么?因为UI is Not Data,因此您应该将应用程序逻辑基于数据项的状态。

    我建议你阅读thisthis

    尝试以与使用 winforms 相同的方式使用 WPF 是通向悲惨失败和痛苦的直接途径。

    您必须接受 MVVM 并了解 DataBinding 以及 UI 如何必须始终与应用程序逻辑和数据分开。

    编辑:添加代码示例(在 C# 中)

    视图模型:

    public class MainViewModel
    {
        public string ButtonContent {get;set;} //TODO: Add Property Change Notification
    
        public MainViewModel()
        {
            ButtonContent = "SomeButtonContent";
        }
    }
    

    查看:

    <Button Width="200" Height="30" Margin="5,5,5,5">
        <TextBlock FontSize="14" Text="{Binding ButtonContent}"/>
    </Button>
    

    代码背后:

    public class MainWindow: Window
    {
        public MainWindow()
        {
            InitializeComponent();
            SomeModule.Instance = new MainViewModel();
            DataContext = SomeModule.Instance;
        }
    }
    

    模块(C# 中的静态类):

    public static class SomeModule
    {
        public static MainViewModel Instance {get;set;}
    
        public void DoSomething()
        {
            if (Instance.ButtonContent == "SomeButtonContent")
                //...etc
        }
    }
    

    这就是我将 UI 与数据分开的意思。您将字符串放在 ViewModel 中,而不是 View 中,然后评估这些 ViewModel 属性的值以确定要做什么。

    不过,将应用程序逻辑基于字符串的值似乎是一个弱解决方案。你真正需要做什么?有更好的方法,例如为此使用 Enum。

    编辑2:

    拥有要绑定的 ViewModel 不会使事情“复杂化”。它实际上简化了很多。

    怎么样?因为您现在使用简单的控件来执行此操作,但随后您会希望对 ControlTemplate 或更糟的 DataTemplate 中的 UI 元素执行相同的操作,这才是真正的问题出现的时候。

    因此,在处理更复杂的 UI 场景之前,您必须习惯“WPF 方式”。

    非最优方法:

    public class MainWindow: Window
    {
         public string ButtonContent
         {
             get
             {
                 return this.txtButtonContent.Text;
             }
             set
             {
                 this.txtButtonContent.Text = value;
             }
         }
    }
    
    <Button Width="200" Height="30" Margin="5,5,5,5">
        <TextBlock x:Name="txtButtonContent" FontSize="14" Text="Connect"/>
    </Button>
    

    您必须了解 Button 类在 WPF 中没有 Text 属性。与大多数古老的框架相比,WPF 有一个 Content Model,其中 anything 可以包含任何东西,几乎没有限制。将Text 属性添加到 Button 将引入 Button 仅包含文本的限制,而 WPF 中并非如此。

    因此,您在此处实际要做的是修改TextBlockText 属性(它恰好位于按钮内部,但实际上可能位于可视树中的任何位置)。

    这就是为什么我提到您实际上需要一个 ViewModel 来保存您的数据这一事实,因为没有(简单的)方法可以访问位于例如 DataTemplate 中的 UI 元素以操作它们。您的 UI 必须始终反映应用程序数据的状态,这些数据存储在 Model 或 ViewModel 类中,而不是 UI。

    【讨论】:

    • 很抱歉,您能否通过代码示例说明您的意思?基本上我的 XAML 中有一个连接按钮。它在 Module_Connection 中调用 Connect() Sub。该按钮必须在例程之后将其文本更改为已连接或已断开连接。
    • @RyanMcKenna 使用示例进行了编辑。你有很多阅读要做。 WPF 确实不同于古老的传统 UI 框架,需要非常不同的心态。同样,我建议您在 Rachel's Blog 中阅读该内容
    • 我发现这一切有点莫名其妙。尝试将您的代码从 C# 转换为 VB 以尝试此操作,但出现错误。你看,我不希望这一切都基于字符串的值,但按钮必须反映我通过切换到“断开连接”来连接的事实。我不明白为什么它必须如此困难并涉及“ViewModels”。
    • @RyanMcKenna 我明白了,我会更新示例。我不明白你在追求什么。
    • 感谢您迄今为止的帮助。
    【解决方案2】:

    这应该让你在球场上:

    模块: 公共子连接(RyRef txtBox 作为文本框) 如果 txtBox.Text = "...

    注意公共与私人

    调用: 调用 .Connect(MyTextBox1)

    调用并且是可选的

    【讨论】:

    • 抱歉,这对我没有帮助。在 Module.vb 上编写代码时,我只需要知道如何声明 MainWindow 上的控件(带有 x:Name="Connection_Button")
    • 更重要的是,如何从声明的按钮中找到按钮内的 TextBlock。
    • 对不起 - 我期待 wpf 类似于 WinForms - 我很傻。
    【解决方案3】:

    我将在 VB.NET 中回答您的问题,并且不提供替代方法的 C# 示例,如果您不习惯的话,这可能是一场艰苦的斗争。

    在你的模块中声明这个,通过 rootWindow 访问控件。

    Private rootWindow As MainWindow = TryCast(Application.Current.MainWindow, MainWindow)
    

    【讨论】:

      【解决方案4】:

      另一种方法是:

      Dim mw as MainWindow = Application.Current.Windows.OfType(Of MainWindow).First
      

      假设您有一个 MainWindow 并且只有一个 MainWindow。

      【讨论】:

        猜你喜欢
        • 2017-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多