I am developing my first Windows 8 app, in one page i am trying to update button text with latest timestop when page loads. I defined my xaml and codebehind like below:
I am using databinding to update the button text but it is not working as expected:
MainPage.xaml
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Button HorizontalAlignment="Left" Margin="333,284,0,0" VerticalAlignment="Top" Height="69" Width="162">
<Button.Resources>
<DataTemplate x:Key="DataTemplate1">
<Grid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding ButtonText}" VerticalAlignment="Top" Foreground="#FFFF6800" Height="34" Margin="-30,0,-22,-14" Width="115"/>
</Grid>
</DataTemplate>
</Button.Resources>
<Button.ContentTemplate>
<StaticResource ResourceKey="DataTemplate1"/>
</Button.ContentTemplate>
</Button>
</Grid>
MainPage.xaml.cs
public StatsClass Stats { get; private set; }
public MainPage()
{
this.InitializeComponent();
this.DataContext = Stats;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
UpdateButton();
}
private void UpdateButton()
{
if (Stats == null)
Stats = new StatsClass();
Stats.ButtonText = DateTime.Now.ToString();
}
StatsClass.cs
public class StatsClass : INotifyPropertyChanged
{
private string _buttonText;
public string ButtonText
{
get
{
return _buttonText;
}
set
{
_buttonText = value;
OnPropertyChanged("ButtonText");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
You have set Content of your Button twice, once with Content="Button" and again with.Button.ContentTemplate. You could just have:
<Button HorizontalAlignment="Left" Margin="333,284,0,0" VerticalAlignment="Top" Height="69" Width="162">
<Grid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding ButtonText}" VerticalAlignment="Top" Foreground="#FFFF6800" Height="34" Margin="-30,0,-22,-14" Width="115"/>
</Grid>
</Button>
I had a similar issue yesterday using binding in a DataTemplate. I guess that you also had a binding error in the debug output.
I solved it using a relative source like that:
<TextBlock Text={Binding DataContext.ButtonText,
RelativeSource={RelativeSource FindAncestor, AncestorType=*YourControl*}}"/>
The Template has no direct access to the datacontext. By using the relative source you can bind to its properties.
Related
I'm trying to display a variable that might change overtime, i tried this :
<Grid HorizontalAlignment="Left" Margin="2,5,0,0" VerticalAlignment="Top" Visibility="{Binding Req_Hexa}">
<TextBlock x:Name="myTextBox" HorizontalAlignment="Left" Height="106" Margin="270,95,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="187" Text= "{Binding Path = myText, ElementName=windowElement, Mode=TwoWay}" />
<TextBox x:Name="Val_Buffer_ReqHexa" HorizontalAlignment="Left" Height="Auto" Margin="52,0,0,0" TextWrapping="Wrap" Text="{Binding Buffer}" VerticalAlignment="Top" MinWidth="100" MaxWidth="500" KeyDown="Properties_KeyDown"/>
</Grid>
public string myText {get; set;}
public void test()
{
myText = " testttttttttttttttttttt";
}
The variable result is supposed to be displayed here but instead there is a blank
I tried every way of displaying a variable I could find
Try to set UpdateSourceTrigger to PropertyChanged:
<TextBlock Text= "{Binding myText, ElementName=windowElement, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Buffer, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
and implement INotifyPropertyChanged:
public string myText
{
get;
set
{
RaisePropertyChanged(myText);
}
}
public void test()
{
myText = " testttttttttttttttttttt";
}
public new event PropertyChangedEventHandler? PropertyChanged;
protected virtual void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Edit:
We got the problem. In WPF you need to have a Page (Diag_Prog.xaml) and a code behind file (Diag_Prog.xaml.cs) which are connected automatically. Just add a page to your project:
In Visual Studio it should look like this:
I am a newbie in WPF, I have a problem concern binding two different ViewModels to two UserControls
that will be attached to two Tabpages in a Tabcontrol.
My code snippets are as follows:
MainWindow.xaml
<Window.Resources>
<local:UserControl1Model x:Key="Control1Model" />
<local:UserControl2Model x:Key="Control2Model" />
</Window.Resources>
<Grid HorizontalAlignment="Left" Height="330" VerticalAlignment="Top" Width="592">
<Grid HorizontalAlignment="Left" Height="45" Margin="0,330,-1,-45" VerticalAlignment="Top" Width="593">
<Button Content="Button" HorizontalAlignment="Left" Margin="490,5,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
<TabControl HorizontalAlignment="Left" Height="330" VerticalAlignment="Top" Width="592" >
<TabItem x:Name="UserControl1TabItem" Header="User Control 1" >
<Grid x:Name="UserControl1Tabpage" Background="#FFE5E5E5" Margin="0,0,-4,-2" Height="300" VerticalAlignment="Top" IsEnabled="true" >
<local:UserControl1 VerticalAlignment="Top" DataContext="{Binding Source={StaticResource Control1Model}}" />
</Grid>
</TabItem>
<TabItem x:Name="UserControl2TabItem" Header="User Control 2">
<Grid x:Name="UserControl2Tabpage" Background="#FFE5E5E5">
<local:UserControl2 VerticalAlignment="Top" DataContext="{Binding Source={StaticResource Control2Model}}" />
</Grid>
</TabItem>
</TabControl>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private UserControl1Model _userControl1Model = new UserControl1Model();
private UserControl2Model _userControl2Model = new UserControl2Model();
public MainWindow()
{
InitializeComponent();
_userControl1Model.Message = "Hello";
_userControl2Model.Message = "Test";
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Will do something
}
}
UserControl1Model.cs
public class UserControl1Model : INotifyPropertyChanged
{
private string _message;
public string Message
{
get { return _message; }
set
{
_message = value;
OnPropertyChanged("Message");
}
}
public UserControl1Model()
{
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string message)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(message));
}
}
#region INotifyPropertyChanged Members
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
For trying purpose, the content of UserControl2Model.cs is as same as UserControl1Model.cs
UserControl1.xaml
<UserControl.Resources>
<app:UserControl1Model x:Key="Control1Model" />
</UserControl.Resources>
<Grid Margin="0,0,0,42" DataContext="{Binding Source={StaticResource Control1Model}}">
<Label Content="Test:" HorizontalAlignment="Left" Margin="48,57,0,0" VerticalAlignment="Top" Width="47"/>
<TextBox x:Name="Conrol1ModelTextbox" HorizontalAlignment="Left" Height="23" Margin="90,59,0,0" TextWrapping="Wrap"
Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top" Width="466" />
</Grid>
UserControl1.xaml.cs
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
}
UserControl2.xaml
<UserControl.Resources>
<app:UserControl2Model x:Key="Control2Model" />
</UserControl.Resources>
<Grid Margin="0,0,0,42" DataContext="{Binding Source={StaticResource Control2Model}}">
<Label Content="Test:" HorizontalAlignment="Left" Margin="48,57,0,0" VerticalAlignment="Top" Width="47"/>
<TextBox x:Name="Conrol2ModelTextbox" HorizontalAlignment="Left" Height="23" Margin="90,59,0,0" TextWrapping="Wrap"
Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top" Width="466" />
</Grid>
For trying purpose, the content of UserControl2.xaml.cs is as same as UserControl1.xaml.cs
My problem is the initial values, "Hello" and "Test" for the two user controls, which are initialized in MainWindow.xaml.cs cannot
be "binded" into the user controls textboxes. What am I doing wrong or missing?
When you declare resources like this
<Window.Resources>
<local:UserControl1Model x:Key="Control1Model" />
<local:UserControl2Model x:Key="Control2Model" />
</Window.Resources>
You are actually constructing new instances of UserControl1Model and UserControl2Model instead using the ones you declared in MainWindow.cs
Also you are not creating any ViewModel for the MainWindow. You should create a MainWindowViewModel like such
public class MainWindowViewModel : INotifyPropertyChanged
{
public ViewModelLocator
{
this.FirstModel= new UserControl1Model
{
Message = "Hello";
}
this.SecondModel = new UserControl2Model
{
Message = "Test";
}
}
private UserControl1Model firstModel
public UserControl1Model FirstModel
{
get
{
return this.firstModel;
}
set
{
this.firstModel= value;
OnPropertyChanged("FirstModel");
}
}
// Same for the UserControl2Model
// implementation of the INotifyPropertyChanged
}
Also you would need to set the DataContext for the MainWindow.
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
And remove the resources from the UserControl xamls. You are already defining the DataContext in the MainWindow.xaml but the binding should be bound from the MainWindowViewModel as such.
<local:UserControl1 VerticalAlignment="Top" DataContext="{Binding FirstModel}" />
Create a ViewModelLocator. you can find various sites on the internet for this subject.
a simple one would be:
public class ViewModelLocator
{
public UserControl1Model UserControl1Model { get; set; } = new UserControl1Model();
public UserControl2Model UserControl2Model { get; set; } = new UserControl2Model();
public ViewModelLocator
{
UserControl1Model.Message = "Hello";
UserControl2Model.Message = "Test";
}
}
then you can use it in your views
<UserControl.Resources>
<app:ViewModelLocator x:Key="ViewModelLocator" />
</UserControl.Resources>
<Grid Margin="0,0,0,42" DataContext="{Binding UserControl2Model Source={StaticResource ViewModelLocator}}">
<Label Content="Test:" HorizontalAlignment="Left" Margin="48,57,0,0" VerticalAlignment="Top" Width="47"/>
<TextBox x:Name="Conrol2ModelTextbox" HorizontalAlignment="Left" Height="23" Margin="90,59,0,0" TextWrapping="Wrap"
Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top" Width="466" />
</Grid>
Suppose, I create this instance in the xaml as follows: <Window.Resources> <local:MainWindowViewModel x:Key="MainWindowViewModel" /> </Window.Resources> instead of creating inside MainWindow.xaml.cs. Then, how can I reference this instance inside MainWindow.xaml.cs, e.g. to get value from MainWindowViewModel.ViewModelLocator.FirstModel.Message ?
Like this:
MainWindowViewModel viewModel = this.Resources["MainWindowViewModel"] as MainWindowViewModel;
//access any properties of viewModel here...
I create a image edit software with images thumbnail viewer. I have a function that is Rotate image, user select a photo and click on button. The problem is i donĀ“t want to refresh all the ListBox. So this code:
ImageListbox.Items.Refresh(); //Very slow if i have more than 100 imgs.
I Want a INotifyPropertyChanged just for BitmapImage.
XAML:
<ListBox Grid.Row="0" x:Name="ImageListbox" VirtualizingPanel.IsVirtualizing="true"
VirtualizingPanel.VirtualizationMode="Recycling" SelectionChanged="ImageListbox_SelectionChanged" MouseDoubleClick="ImageListbox_MouseDoubleClick"
ItemsSource="{Binding Path=Model}"
Background="AliceBlue" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Margin="0,0,2,0" Grid.RowSpan="2">
<ListBox.ContextMenu>
<ContextMenu x:Name="MenuContext">
<MenuItem Header="Abrir imagem (Prova)" Click="MenuItem_Click"/>
<MenuItem Header="Abrir imagem (Original)" Click="MenuItemOriginal_Click"/>
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="stack1" Height="330" Width="285" Margin="2,2,2,2" >
<WrapPanel>
<TextBlock Text="{Binding Path=ImgName}" Margin="5,0,0,0" FontSize="16" ></TextBlock>
<CheckBox Height="20" x:Name="chkUniqueId" IsChecked="{Binding Path=CheckBox}" Margin="5,0,0,0" Click="chkUniqueId_Click"/>
</WrapPanel>
<Image Margin="5,5,5,5" Height="300" Width="280" VerticalAlignment="Top" >
<Image.Source>
<BitmapImage x:Name="ImageSource" DecodePixelWidth="300" CacheOption="None" UriSource="{Binding Path=ImgPath}" />
</Image.Source>
</Image>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C#
public class ReportagemItems : ObservableCollection<ReportagemItem>
{
public ReportagemItems() { }
}
public class ReportagemItem : INotifyPropertyChanged
{
//i have more 2 properties here, not necessary for this example.
private string _ImgName;
public string ImgName
{
get { return this._ImgName; }
set
{
if (this._ImgName != value)
{
this._ImgName = value;
this.NotifyPropertyChanged("ImgName");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
//in Btn Click event i have:
List<ReportagemItem> changeItem = ImageListbox.Items.OfType<ReportagemItem>().Where(x => x.CheckBox).ToList();
foreach (var item in Model.Where(x => x.ImgPath == changeItem.First().ImgPath))
{
item.CheckBox = false; //WORKS
item.ImgName = "New Name"; //WORKS
item.ImgPath = #"C:\Programa Provas\Destino\Performance15\Uteis\Thumb\1.JPG"; //DOESNT WORK...
}
Bind the Source property of the Image element, either directly to the source property:
<Image Margin="5,5,5,5" Height="300" Width="280" VerticalAlignment="Top" Source="{Binding Path=ImgName}"/>
...or by using a converter that creates and returns a BitmapImage: https://social.msdn.microsoft.com/Forums/vstudio/en-US/ea1fd63b-738c-40ca-850e-994eb21dccea/binding-to-image-source-via-valueconverter-and-datacontext-in-usercontrol?forum=wpf
I have a UserControl with several TextBox controls and a ProgressBar. The TextBox controls properly reflect the properties in codebehind to which they are bound. The ProgressBar does not respond to property change, however.
My XAML:
<UserControl
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:Controls="clr-namespace:Cmc.Installer.Controls;assembly=Cmc.Installer.Controls" x:Class="Cmc.Installer.Modules.MobileRecruiter.MobileRecruiterModule"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<Grid HorizontalAlignment="Left" Height="580" Margin="10,10,0,0" VerticalAlignment="Top" Width="780">
<Canvas>
<Label Content="Database Server" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<TextBox Text="{Binding DatabaseServer}" Height="23" Canvas.Left="160" Canvas.Top="12" Width="160"/>
<Label Content="Database Name" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="38"/>
<TextBox Text="{Binding DatabaseName}" Height="23" Canvas.Left="160" Canvas.Top="40" Width="160"/>
<Label Content="Database Username" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="66"/>
<TextBox Text="{Binding DatabaseUsername}" Height="23" Canvas.Left="160" Canvas.Top="68" Width="160"/>
<Label Content="Database Password" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="94"/>
<Controls:BindablePasswordBox Password="{Binding DatabasePassword}" Height="23" Canvas.Left="160" Canvas.Top="96" Width="160"/>
<ProgressBar Name="ProgressBar" Value="{Binding Progress}" Minimum="0" Maximum="100" Canvas.Left="10" Canvas.Top="164" Width="760" Height="24" />
</Canvas>
</Grid>
</UserControl>
And its codebehind (very abbreviated):
public partial class MobileRecruiterModule : UserControl, INotifyPropertyChanged
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private int _progress;
public MobileRecruiterModule()
{
InitializeComponent();
DataContext = this;
}
public string DatabaseServer { get; set; }
public string DatabaseName { get; set; }
public string DatabaseUsername { get; set; }
public string DatabasePassword { get; set; }
public int Progress
{
get { return _progress; }
set
{
if (value == _progress) return;
_progress = value;
OnPropertyChanged("Progress");
Logger.Trace("Progress.set() = " + _progress);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
// This is called by an external class
public void OnProgressChanged(object sender, ProgressChangedEventArgs args)
{
Progress = args.ProgressPercentage;
}
}
I know the value of Progress is changing because I see it in the NLog logs:
2014-04-17 16:22:54.4068|TRACE|Cmc.Installer.Modules.MobileRecruiter.MobileRecruiterModule|Progress.set() = 28
I don't understand why the ProgressBar doesn't update when I fire OnPropertyChanged in the setter just before the logging call.
I replicated a scaled down version of your app in an MVVM pattern and had good luck with it. I used this code to replicate your user control...
<UserControl x:Class="ProgressBarBinding.Login"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid HorizontalAlignment="Left" Height="580" Margin="10,10,0,0" VerticalAlignment="Top" Width="780">
<Canvas>
<Label Content="Database Server" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<TextBox Text="{Binding DatabaseServer}" Height="23" Canvas.Left="160" Canvas.Top="12" Width="160"/>
<Label Content="Database Name" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="38"/>
<TextBox Text="{Binding DatabaseName}" Height="23" Canvas.Left="160" Canvas.Top="40" Width="160"/>
<Label Content="Database Username" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="66"/>
<TextBox Text="{Binding DatabaseUsername}" Height="23" Canvas.Left="160" Canvas.Top="68" Width="160"/>
<Label Content="Database Password" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="94"/>
<ProgressBar Name="ProgressBar" Value="{Binding Progress}" Minimum="0" Maximum="100" Canvas.Left="10" Canvas.Top="164" Width="760" Height="24" />
</Canvas>
</Grid>
</UserControl>
The only thing missing from that is your proprietary password control, which does not affect the solution.
I encoded this control into a MainWindow.xaml file thusly...
<Window x:Class="ProgressBarBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ProgressBarBinding"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<vm:ViewModel x:Key="ViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource ViewModel}">
<vm:Login/>
</Grid>
</Window>
Note that the window resource definition includes a reference to a view model instance. Most people set up MVVM with dependency injection, but this approach is good for quick trials and Indicative Code. The view model is set as the Grid's data context. Your control inherits the data context from the grid. That's the end of the xaml code. There is no code-behind in the MainWindow.xaml.cs file other than the call to InitializeComponent (and that's where the VM instance gets created).
The ViewModel class looks like this...
public class ViewModel : INotifyPropertyChanged
{
private readonly SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
public ViewModel()
{
DatabaseServer = "AnyServer";
DatabaseName = "Any name";
Model m = new Model();
Task.Run(() => m.DoWork(this));
}
public string DatabaseServer { get; set; }
public string DatabaseName { get; set; }
public string DatabaseUsername { get; set; }
public string DatabasePassword { get; set; }
private int _progress;
public int Progress
{
get { return _progress; }
set
{
if (value == _progress) return;
_progress = value;
OnPropertyChanged("Progress");
Console.WriteLine(#"Progress.set() = " + _progress);
}
}
// This is called by an external class
public void OnProgressChanged(object sender, ProgressChangedEventArgs args)
{
_synchronizationContext.Send(delegate { Progress = args.ProgressPercentage; }, null);
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
Most of the code in the view model looks like yours except there are no dependencies on UI elements. Everything is done via binding. I used a SynchronizationContext in the callback, although it may not be necessary in your application.
The constructor of the VM starts a model on a TPL thread. The model looks like this...
public class Model
{
public void DoWork(ViewModel vm)
{
int progressPercentage = 0;
for (int i = 0; i < 100000; i++)
{
vm.OnProgressChanged(this, new ProgressChangedEventArgs(progressPercentage, null));
if (i%1000 == 0)
{
++progressPercentage;
}
}
}
}
So putting it all together, the model is running in its own thread, and the UI is being updated on its own thread. The whole thing works as expected.
The ProgressBar will increment its way up to 100 and the UI will remain responsive while the model is doing its work. This answer does not explain why your original code does not work, but I suspect it has to do with the UI thread being starved out. This is evidenced by your complete log history, but nothing changing on the UI. Overall, this answer moves toward what others have suggested in their commentary: namely that the MVVM approach of binding has a lot to offer.
Since you're in a UserControl, you need to explicitly give it a name and use the ElementName tag when binding, like this:
<UserControl
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:Controls="clr-namespace:Cmc.Installer.Controls;assembly=Cmc.Installer.Controls" x:Class="Cmc.Installer.Modules.MobileRecruiter.MobileRecruiterModule"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800" x:Name="MyControl">
<Grid HorizontalAlignment="Left" Height="580" Margin="10,10,0,0" VerticalAlignment="Top" Width="780">
<Canvas>
<ProgressBar Name="ProgressBar" Value="{Binding Progress, ElementName=MyControl}" Minimum="0" Maximum="100" Canvas.Left="10" Canvas.Top="164" Width="760" Height="24" />
</Canvas>
</Grid>
</UserControl>
Why do you need Binding if you have the Actual control. Since you are not doing it in MVVM just call the ProgressBar right away.
ProgressBar.Dispatcher.Invoke(() => ProgressBar.Value = Progress = args.ProgressPercentage);
Sorry but I don't see the benefit of the Binding if all the properties/controls are accessible in your View's class.
Binding is more useful and powerful if you implemented MVVM.
Here's the code for my window:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="leartWPF.ControlTestWindow"
x:Name="Window"
Title="ControlTestWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<TextBlock Height="26" Margin="45,26,241,0" TextWrapping="Wrap" Text="Please, enter an ariphmetical expression to calculate:" VerticalAlignment="Top"/>
<TextBox Margin="48,72,63,201" TextWrapping="Wrap" Text="{Binding Input, ElementName=Window, FallbackValue=1+1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" TextChanged="TextBox_TextChanged" >
</TextBox>
<!--<TextBlock Margin="282,208,266,167" TextWrapping="Wrap" Text="=" FontSize="64"/>-->
<TextBlock Height="90" Margin="83,0,77,60" TextWrapping="Wrap" VerticalAlignment="Bottom" FontSize="48" Text="{Binding Result, ElementName=Window, Mode=TwoWay}"/>
<Button Content="=" Height="27" Margin="233,0,263,166" VerticalAlignment="Bottom" FontSize="16"/>
</Grid>
</Window>
and the class:
public partial class ControlTestWindow : Window
{
private string _input;
public double Result { get; set; }
private static VsaEngine _engine = VsaEngine.CreateEngine();
public string Input
{
get { return _input; }
set
{
Result = double.Parse(Eval.JScriptEvaluate(value, _engine).ToString());
_input = value;
}
}
public ControlTestWindow()
{
this.InitializeComponent();
// Insert code required on object creation below this point.
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
}
}
The Input gets updated, and Result value changes, but it is never displayed on the appropriate TextBlock.
What should I change for this to work?
The TextBlock doesn't get notified of the change to the Result property. You have two options:
Implement the property as a DependencyProperty. Visual studio has a code snippet for it. Type propdp and you'll see it pop up in intellisense.
Implement INotifyPropertyChanged on your Window class and use it in your property.