Reload a image using ReactiveUI and WPF - wpf

I am trying to change a image in the UI running with WPF on runtime by changing the source of the image. Unfortunately the image is not changing. I found examples of using a Bitmap image to change the Image source, but with ReactiveUI I am not able to change the UriSource for the BitmapImage.
XAML code:
<Image x:Name="button_image0" DockPanel.Dock="Top" Source="someimage.jpg" Stretch="Uniform" />
view code:
this.OneWayBind(ViewModel, vm => vm.button_image0, v => v.button_image0).DisposeWith(d);
Viewmodel code:
[Reactive] public string button_image0 { get; set; }
//button pressed
button_image0 = "newimage.jpg";
I checked that the source of the image is changing, but the image displayed is not. Does someone know how to solve this with reactiveUI or knows a way around?
Solution
If anyone is having the same problem, it's a syntax error of your code. When changing the source of an image using reactiveUI the image is reloaded. This question and answer confused me Reloading an image in wpf

When binding you should include the control property as part of the expression. For example
ContentControl.Content
SizableControl.Width
Image.Source
TextBlock.Text
So if you bind to the "Source" property on the Image on the view. You also appear to have your notation of v and vm the wrong way around which might be adding to the confusion. The viewmodel is the 2nd expression, the view is the 3rd.
this.OneWayBind(ViewModel, vm => vm.button_image0, vw => vw.button_image0.Source).DisposeWith(d);

Related

Add DependencyObject to control from code-behind

I want to add a DependencyObject to a control from code behind. I have searched and searched online for how to do this with absolutely no success. The DependencyObject has a DependencyProperty. I also want to set this property from code-behind.
charting:ChartBehaviors inherits directly from DependencyObject. It is a class I wrote myself. The Chart control is a Third-party control.
charting:ChartBehaviors.FloatingTooltip is the DependencyProperty. This is also a class I wrote myself.
Here is what it looks like in XAML. I want to do this in code behind so that I can turn on and off the "behavior".
<charting:Chart>
<charting:ChartBehaviors.FloatingTooltip>
<charting:FloatingTooltipBehavior
TooltipTemplate="{StaticResource tooltipTemplate}" />
</charting:ChartBehaviors.FloatingTooltip>
</charting:Chart>
You can just use the SetValue method on the object (assuming you give your chart an id of chart1).
var behave = new FloatingTooltipBehavior();
chart1.SetValue(ChartBehaviors.FloatingTooltipProperty, behave);
Another solution would be to just add an Enabled property to your behavior and then set that from the code behind.
Well, you basically instantiate necessary dependency object and use appropriate method to add it to the control. For example, to add TextBlock to the StackPanel, you write it like this:
TextBlock txtMyText = new TextBlock();
stackPanel.Children.Add(txtMyText);
If you're wanting to add certain behavior to a chart, you should just get your chart object in code and look for a property like Behaviors or something. Then you either assign a behavior (if it's one-behavior-only) or add it like to the stackpanel:
Chart myChart;
myChart.Behavior = new FloatingTooltipBehavior();
It's hard to tell the exact syntax without knowing the component.

How to set the default binding converter in Wpf?

I'm moving project from Silverlight to WPF and I've come across a problem.
I have a control with an INotifyPropertyChanged property GeoRect of type GeoRect. GeoRect has a variety of public properties that are set in its constructor each of type IGeoPosition.
I am setting a binding to one of these properties like so:
<TextBlock Text="{Binding GeoRect.TopRight, ElementName=x_SomeControl}"></TextBlock>
In Silverlight the default ToString method is called on IGeoPosition instance every time the GeoRect property changes. In Wpf I don't get any text at all.
I can correct this in Wpf by adding a ValueConverter to the TextBlock which simply calls the ToString method on the object, but this appears to be unnecessary fat. Can anyone help?
I suspect that there is another problem in your binding. Also in WPF, data binding calls the ToString() method to build the text of a Text-control.
Have you checked the output window of visual studio for a binding error? Or maybe the GeoRect-class does not support INotifyPropertyChanged for the TopRight property?
I guess that ElementName=x_SomeControl and GeoRect.TopRight are causing a probable "Source and Path" comination error. Are you sure your x_SomeControl has a property called 'GeoRect'? Also is x_SomeControl.GeoRect not null? And x_SomeControl.GeoRect.TopRight has a correct value?
As HCL pointed out, this will become apparent when you view your Output window where BindingExpression error must have appeared for this binding.
Please check.

Using Image Control in Silverlight (4)

I'm trying to use the Image control is a very basic way, like here:
http://www.silverlightshow.net/items/Using-the-Image-control-in-Silverlight-2-Beta-1.aspx
So I'm ending up with XAML like this:
<Image x:Name="imgSmall" Stretch="Fill" Source="../Img/Small/105.jpg" Margin="10,0,0,0"></Image>
Which isn't working. The Image is blank, and in the designer the URI is underlined with a message of "...is not part of the project or its build action is not set to 'Resource"
If I change the source to a property on my ViewModel, set like this:
new Uri(App.Current.Host.Source, "../Img/Small/105.jpg");
Then it works fine. I'd much prefer to use the simpler syntax and get the image directly. Is this possible?
(The images are one level up from ClientBin)
Setting all of my web sites images to build=Resource is not possible.
Thanks!
You have to create a converter that takes the relative image path and adds the "absolute" part. You can pass the relative Uri as binding value or as converterParameter.
class ImageConverter : IValueConverter
{
// method convert()
return new BitmapImage(new Uri(App.Current.Host.Source, ((string)parameter));
//...
}
It id doesn't work because image is not added to your project.
Add image to project and in then you can set source from xaml.

How is the DataContext typically set?

I've created a new WPF project, and threw in a DataGrid. Now I'm trying to figure out the easiest way to bind a collection of data to it.
The example I downloaded seems to do it in the window c'tor:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
But then the bindings don't seem to appear in the Visual Studio's Properties window. I'm pretty sure there's a way to set the data context in XAML too... it would make me even happier if I could do it directly through the properties window, but all the Binding options are empty. What's the typical approach?
Edit: At 14 minutes, he starts to talk about other methods of setting the data context, such as static resources, and some "injection" method. I want to learn more about those!
What I typically do is use MVVM. You can implement a simplified version by setting the data context in your code behind and having a model type class that holds your data.
Example: In your code behind
DataContext = Model; // where Model is an instance of your model
then in your view
<DataGrid .... ItemsSource="{Binding SomeProperty}">....
Where SomeProperty is an enumerable property on your view model
You can also set a data context in XAML by using the DataContext property
<uc:SomeUserControl DataContext="{Binding AnotherProperty}"....
This will run your user control within the DataContext of the AnotherProperty on your model.
Note that this is grosely simplified but it'll get you on your way.
Have a look at the MVVM design pattern. This pattern is very suitable for wpf applications.
There is described where to store your data and how to bind your ui to the data.

Can you use data binding with the Content property of a WPF Frame?

I can use data binding to set the initial Content of a WPF Frame, but subsequent changes to the the bound property (implemented using INotifyPropertyChange) do not seem to change the content.
Also, does anyone know if binding directly to the Content property in this way will cause the bound item to appear in the Frame or NavigationWindow's journal?
Some context: I realize that I should probably be using the NavigationService to interact with the Frame, but I'm attempting to follow the MVVM pattern. It seems like it would be much simpler to databind to the Content property...
You can use data binding against a Frame, but you need to make sure the Mode for your Binding is set to TwoWay.
XAML:
<Frame Content={Binding Path=MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} />
View Model:
public class MyViewModel : INotifyPropertyChanging, INotifyPropertyChanged
{
public Page MyProperty
{
get
{
return _viewModelPage;
}
set
{
this.OnPropertyChanging("MyProperty");
_viewModelPage = value;
this.OnPropertyChanged("MyProperty");
}
}
}
Many in the WPF community agree that the built-in navigation framework is broken. However, even if you were to use it, binding the Content property is not the correct approach. If you want to use MVVM with navigation you should combine it with the FrontController pattern where the ViewModel dispatches a navigation request to a Controller which then resolves that request for you. There aren't many examples of this concept available because (as I mentioned before) many developers pass on using WPF's built-in navigation.
If you want to look at a very robust navigation engine for WPF, look at nRoute It is a port of the MVC routing engine to WPF.
The Frame is a navigation host, so it is more correct to use the NavigationService to navigate to different content. If you use the INotifyPropertyChange, I suppose that you call the related event whenever the content is changed. Then, I also suppose that there is no difficult to use the NavigationService instead.
I ran into this issue a few days ago. I had a main window with a frame, and I loaded different pages into the frame (by using Navigate()). The pages' data bindings were broken, the data did not show up on the loaded page.
To repair the bindings, create or give your existing DataContext to the page inside the frame, and the bindings will work again.

Resources