0

I am new to WPF/XAML.

I am making a scrolling marquee using a demo I found online. It is WinForms using a HostedElement WPF custom User Control.

I was able to setup a class called MyModelView so that I can bind the text value of a textblock to a variable I control (MyTextProperty).

But I can't figure out how to change the variable. My goal is to have a textbox you can enter text into and it will bind to the textblock value and change it while the program is running.

I am not able to do this, which I am trying to do (Change bound variable to TextBox1 value - it is not a valid reference to the variable... what is?):

Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
    MyViewModel.MyTextProperty = TextBox1.text
End Sub

How do I reference that class variable to change the text? I am missing something.

MyViewModel.vb

Imports System.ComponentModel

Public Class MyViewModel
    Implements INotifyPropertyChanged

    Public Sub New()
        Me.myTextValue = "WINNING!!!"
    End Sub

    Private myTextValue As String = String.Empty
    Public Property MyTextProperty() As String
        Get
            Return Me.myTextValue
        End Get

        Set(ByVal value As String)
            Me.myTextValue = value
            NotifyPropertyChanged("MyTextProperty")
        End Set
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler _
        Implements INotifyPropertyChanged.PropertyChanged

    Private Sub NotifyPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

End Class

Scrolling Marque.xaml

<UserControl x:Class="ScrollingMarquee"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:interopdemo="clr-namespace:InteropDemo"
    mc:Ignorable="d" 
    d:DesignHeight="100" d:DesignWidth="300">
    <UserControl.Resources>
        <Storyboard x:Key="MarqueeScroll">
            <DoubleAnimation RepeatBehavior="Forever" 
                Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" 
                Storyboard.TargetName="spMarquee" 
                From="1500"  To="-500" 
                Duration="0:0:0:7" />
        </Storyboard>
    </UserControl.Resources>
    <Grid>
        <Grid.DataContext>
            <interopdemo:MyViewModel/>
        </Grid.DataContext>
        <StackPanel x:Name="spMarquee" Orientation="Horizontal"  Width="Auto">
            <TextBlock Text="{Binding MyTextProperty}" FontSize="28" VerticalAlignment="Center" Margin="30,0,60,0"/>
            <TextBlock Text="Hello Scrolling Text!" Foreground="Firebrick" FontSize="28" VerticalAlignment="Center" Margin="40,0,60,0"/>
            <TextBlock Text="Ticker 2000!" Foreground="Red" FontSize="28" FontStyle="Italic" FontWeight="Bold" VerticalAlignment="Center" Margin="50,0,80,0"/>
            <StackPanel.RenderTransform>
                <TranslateTransform/>
            </StackPanel.RenderTransform>
        </StackPanel>
    </Grid>
</UserControl>

Form1.vb

Imports System.Windows.Media.Animation

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
        Me.WindowState = FormWindowState.Maximized

        ElementHost1.Visible = True
        Dim storyRunMarquee As Storyboard = ScrollingMarquee1.FindResource("MarqueeScroll")
        storyRunMarquee.Begin()

    End Sub

End Class

I've tried referencing the variable but can't make it work. The scrolling animation displays as "Winning! Hello Scrolling Text! Ticker 2000!" But I'm trying to change the bound "Winning!" text.

Joe
  • 1
  • 5
  • You write about "My goal is to have a textbox you can enter text into ..." , but I don't see any `TextBox` in posted example. – Rekshino Jan 26 '23 at 20:58
  • It's Winforms, so it's on Form1.vb which I didn't post the designer back-end code for. The textblock is called TextBox1. You're seeing XAML in my question because on my form I have an embedded ElementHost which is hosting the XAML UserControl. So this is Winforms with embedded WPF element. – Joe Jan 26 '23 at 21:04
  • What is `MyModelView` from `MyModelView.MyTextProperty = TextBox1.text`? – Rekshino Jan 26 '23 at 21:12
  • Typo - fixed. What I want to do is MyViewModel.MyTextProperty = TextBox1.text but I can't reference it in that way. I need to know how to change it. The variable is bound and works in the animation, I just don't know how to reference. Thanks – Joe Jan 26 '23 at 21:17
  • Side note - for convenience, you may wish to use the `` attribute on the `propertyName` argument of `NotifyPropertyChanged`, then you don't need to write it out at the call site, the compiler will automatically fill it in for you. (When you do this, it needs to become an `Optional` parameter.) – Craig Jan 27 '23 at 16:22

2 Answers2

1

Remove

<Grid.DataContext>
   <interopdemo:MyViewModel/>
</Grid.DataContext>

Declare a member variable in the form to hold reference to the view model object:

Private scrollerViewModel As MyViewModel

Instantiate an object of class MyViewModel in Form1_Load and set it as a DataContext for user control.

Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
   Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
   Me.WindowState = FormWindowState.Maximized

   ElementHost1.Visible = True

   scrollerViewModel = New MyViewModel
   ScrollingMarquee1.DataContext = scrollerViewModel

   Dim storyRunMarquee As Storyboard = ScrollingMarquee1.FindResource("MarqueeScroll")
   storyRunMarquee.Begin()

End Sub

Modify property:

Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
    scrollerViewModel.MyTextProperty = TextBox1.text
End Sub
Rekshino
  • 6,954
  • 2
  • 19
  • 44
  • Syntax can be wrong, I'm not from VB world. – Rekshino Jan 26 '23 at 21:32
  • Thank you for this input It is headed in the right direction I think. When I test the modify property (scrollerViewModel.MyTextProperty = TextBox1.Text), I get a runtime error System.NullReferenceException: 'Object reference not set to an instance of an object.' But you did show me another way to instantiate which I think is closer to the goal. – Joe Jan 27 '23 at 15:08
  • scrollerViewModel.MyTextProperty = "Hello" - this works if I put it into Form1_Load. Is it possible it is out of scope when I put it into the Sub TextBox1_TextChanged? – Joe Jan 27 '23 at 15:14
  • OK wierd. If I put scrollerViewModel.MyTextProperty = TextBox1.Text into a sub for Textbox1_textchanged it does not work (runtime error as noted above) but if I put it into a sub for Button1_Click it works and changes the text scrolling in real time! You did it! I think I can handle this from here! Thank you so much! – Joe Jan 27 '23 at 15:18
  • See also [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Rekshino Jan 27 '23 at 15:41
0

I think you just need to cast the datacontext of ScrollingMarquee1 as MyViewModel

 CType(ScrollingMarquee1.DataContext, MyViewModel).MyTextProperty = TextBox1.text
Andy
  • 11,864
  • 2
  • 17
  • 20