0

I want to use modules in my first WPF application, as I'm used to using them in WinForm applications I've created before. So I have this button, with a textblock inside.

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>

Before in WinForms I could easily reference a button and it's text property by adding MainForm. before the control, but how can I do this in WPF through modules, similar to below? How do I even declare the controls at the top of my module code? And elements inside a control such as TextBlock?

Module_Connection.vb in my old WinForm way:

Private Sub Connect()
        If MainForm.Connection_Button.Text = "Connect" Then
        ' Code
rwmck
  • 25
  • 2
  • 8

4 Answers4

2

You don't usually do this in WPF.

To base your application logic in the state of UI elements is not really a good idea.

Why? because UI is Not Data and therefore you should base your application logic on the state of data items instead.

I suggest you read this and this

To try to use WPF the same way you use winforms is a straight path to miserable failure and suffering.

You must embrace MVVM and understand DataBinding and how the UI must always be separate from Application Logic and Data.

Edit: Adding a Code Sample (in C#)

ViewModel:

public class MainViewModel
{
    public string ButtonContent {get;set;} //TODO: Add Property Change Notification

    public MainViewModel()
    {
        ButtonContent = "SomeButtonContent";
    }
}

View:

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

Code Behind:

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

Module (static class in C#):

public static class SomeModule
{
    public static MainViewModel Instance {get;set;}

    public void DoSomething()
    {
        if (Instance.ButtonContent == "SomeButtonContent")
            //...etc
    }
}

This is what I mean by separating the UI from the data. You place your strings in a ViewModel, not in the View, then you evaluate the value of those ViewModel properties to determine what to do.

Still, basing your application logic on the value of a string seems like a weak solution. What do you really need to do? There are much better approaches such as using an Enum for this.

Edit2:

Having a ViewModel to Bind to does not "complicate" things. It actually simplifies them a LOT.

How? because you're now doing this with simple controls, but then you'll want to do the same thing with UI elements inside a ControlTemplate or even worse a DataTemplate and that's when real problems arise.

Therefore, you must get used to "the WPF Way" before you deal with more complex UI scenarios.

Non-optimal approach:

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>

You must understand that the Button class doesn't have a Text property in WPF. In contrast to most ancient framweworks, WPF has a Content Model where literally anything can contain anything with little to no restrictions. Putting a Text property to the Button would be to introduce the limitation for the Button to only contain Text, which is not the case in WPF.

Therefore, what you actually want to do here is to modify the Text property of the TextBlock (which happens to be inside the Button, but could actually be anywhere in the Visual Tree).

That's why I mentioned the fact that you actually NEED a ViewModel to hold your data, because there is no (easy) way to access the UI elements located, for example within a DataTemplate in order to manipulate them. Your UI must always be a reflection of the state of your application's Data, which is stored in Model or ViewModel classes, not the UI.

Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • I'm sorry, but can you demonstrate what you mean with an example of the code? Basically I have a connect button in my XAML. It calls a Connect() Sub in Module_Connection. The button must change it's text to Connected or Disconnected after the routine. – rwmck Apr 30 '13 at 15:24
  • @RyanMcKenna edited with a sample. You have a lot of reading to do. WPF is really different from ancient traditional UI frameworks and requires a very different mentality. Again, I suggest you read up on that in [Rachel's Blog](http://rachel53461.wordpress.com/2012/10/12/switching-from-winforms-to-wpfmvvm/) – Federico Berasategui Apr 30 '13 at 15:35
  • I'm finding all this a bit baffling. Tried to convert your code from C# to VB to try this out, but I'm getting errors. You see, I don't want all this to be based on the value of the string, but the button must reflect the fact that I am connected by toggling to 'Disconnect'. I don't understand why it has to be so difficult and involve 'ViewModels'. – rwmck Apr 30 '13 at 16:06
  • @RyanMcKenna I see, I'll update the sample. I didn't understand what you were after. – Federico Berasategui Apr 30 '13 at 16:07
  • @RyanMcKenna See the Edit2 – Federico Berasategui Apr 30 '13 at 17:20
  • I've been reading a lot about MVVM since your last edit. I'll take this knowledge on board, thank you. – rwmck May 01 '13 at 08:59
  • The simple answer I was looking for was this. Dim Viz_Machine_TextBox As TextBox = My.Windows.MainWindow.Viz_Machine_TextBox – rwmck May 01 '13 at 14:26
  • @rwmck there's no `"My"` namespace in C#, so I would have been unable to give you such an answer. It's been like 3 years since the last time I did anything in VB.Net =) – Federico Berasategui May 01 '13 at 14:41
  • Well, I appreciate your info on MVVM, but the question was tagged VB.NET. – rwmck May 02 '13 at 14:12
0

This should get you in the ballpark:

Module: Public Sub Connect(RyRef txtBox as TextBox) If txtBox.Text = "...

note Public vs. Private

Call: Call .Connect(MyTextBox1)

Call and are optional

rheitzman
  • 2,247
  • 3
  • 20
  • 36
  • Sorry, but this hasn't helped me. I just need to know how to declare a control that is on MainWindow (with an x:Name="Connection_Button") when writing code on a Module.vb – rwmck Apr 30 '13 at 14:50
  • And more importantly, how do I find the TextBlock inside the button, from a declared button. – rwmck Apr 30 '13 at 14:54
  • Sorry - I was expecting wpf to be similar to WinForms - silly me. – rheitzman Apr 30 '13 at 22:37
0

I'll answer your question in VB.NET and not provide C# samples of alternative ways of doing it which if you're not used too can be an uphill struggle.

Declare this in your module, access the controls through rootWindow.

Private rootWindow As MainWindow = TryCast(Application.Current.MainWindow, MainWindow)
zmo
  • 24,463
  • 4
  • 54
  • 90
Bar
  • 1
0

Another approach is :

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

assuming you have a MainWindow and only have one MainWindow.

Grigory Zhadko
  • 1,484
  • 1
  • 19
  • 33
Mikey
  • 11
  • 3