I have a Big problem there and trying to solve it for so long now...
So what I try to do:
- I add a Button to my Wrapgrid with the Codebehind file
- This button should change a variable which is the Source of an Image
Datenbank database = new Datenbank();
Binding bind = new Binding("ValueGet");
bind.Source = database;
bind.Mode = BindingMode.OneWay;
System.Windows.Controls.Button champbtn = new System.Windows.Controls.Button();
champbtn.Name = "btnAhri";
champbtn.Width = 60;
champbtn.Height = 60;
champbtn.Margin = new Thickness(4);
champbtn.SetBinding(Button.CommandProperty, bind);
champbtn.ToolTip = "Ahri";
champbtn.Content = "Press me";
WrapGrid.Children.Add(champbtn);
This works. I get my Button and its clickable.
Now as you can see I added some Command Binding to my other Class "Datenbank" which look like this:
public class Datenbank : INotifyPropertyChanged
{
private string _Source;
public string ImgSource
{
get { return _Source; }
set
{
_Source = value;
NotifyPropertyChanged("ImgSource");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyname)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
public DelegateCommand ValueGet{ get; set; }
public Datenbank()
{
ValueGet = new DelegateCommand(Ahri);
}
private void Ahri(object sender, EventArgs e)
{
System.Windows.Forms.MessageBox.Show("test");
ImgSource = "Ahri_Square_0.png";
}
}
Here is my DelegateCommand class:
public class DelegateCommand : ICommand
{
public delegate void SimpleEventHandler(object sender, EventArgs e);
private SimpleEventHandler _eventHandler;
public DelegateCommand(SimpleEventHandler eventHandler)
{
_eventHandler = eventHandler;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_eventHandler(this, new EventArgs());
}
}
As you can see the generated button should change the string of "ImgSource"
This variable is bound to an imagebox in my xaml code:
<Image Height="50" Name="image1" Stretch="Fill" Width="50" Source="{Binding ImgSource, Source={StaticResource database}}" />
This is ok aswell. So now my problem is, when I press the generated button my "test" messagebox appears, but the image does not change its source and I really dont know how to fix this.
When I manually add a button with the same command as the generated button above, it works fine!
<Button Command="{Binding ValueGet,Source={StaticResource database}}">Press ME</Button>
It instantly changes the image source and the picture appears, but not with the generatet one and this is important!
So I hope anyone can help me out with this, because I can't find the problem.
The image was not build as resource of application/assembly.
Let try.
Go to Solution explorer.
Right-click on the image
Select Properties
You will see "Build action"
Build action value should be "Resource".
I hope this help.
Related
I have a question. How to bind variables dynamically from ViewModel to View? For now, it not even displayed. If i not using Command, it works great (but of course, i can bind image only once).
My View:
namespace somestuff.View
{
public partial class WindowView : Window
{
public WindowView()
{
this.DataContext = new WindowViewModel();
InitializeComponent();
}
}
}
my View.Xaml (shorten):
<Image Source="{Binding DisplayedImage}"/>
<Button Command="{Binding NewImageCommand}"/>
And my ViewModel:
public WindowViewModel()
{
_canExecute = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string DisplayedImage //displaying image
{
get { return filepath; }
set { filepath = value; NotifyPropertyChanged(nameof(filepath)); }
}
public string filepath { get; set; } //var for binding
private bool _canExecute;
private ICommand _newImageCommand; //command for button
public ICommand NewImageCommand
{
get
{
return _newImageCommand ?? (_newImageCommand = new Commands.CommandHandler(() => GetImage(), _canExecute));
}
}
public void GetImage() { filepath = Pictures.GetNewImage(); } //command on button click
Can you tell me, why after triggering Command GetImage() on button click the image binded on Image not changed? If i move filepath = Pictures.GetNewImage(); from command (more clear, i not use command) all works great, but i cant re-invoke binding to my Image. Can you tell me, how to bind propertis dynamically into View from View model? When value of variable (in this case, filepath) change, i want to change View control too.
Thanks for any advices.
EDIT:
I have 6 Image Labels. I displaying images in it like that:
public BitmapImage DisplayedHighPerformanceImage
{
get { return kMMHP; }
set { kMMHP = value; NotifyPropertyChanged(nameof(kMMHP)); }
}
So i need filepath to init 6 diffrent bitmaps. Then i work on that bitmaps (for exampe, that kMMHP) So i want to display every new bitmap initialized from kMMHP image.
kMMHP = method1(); //displaying it
//other stuff do with diffrent bmps
kMMHP = method2(); //displaying it after second method with changed values
NotifyPropertyChanged must be called with the name of the property, not the name of its backing field. And in order to fire the change notification event, you have to set the property, not the backing field:
public BitmapImage DisplayedHighPerformanceImage
{
get { return kMMHP; }
set { kMMHP = value; NotifyPropertyChanged(nameof(DisplayedHighPerformanceImage)); }
}
DisplayedHighPerformanceImage = method1();
Hi !
I have a WPF application and I want to set the title of the window page without refresh the all page, because in this page I have two buttons that list a DataRow belong the Title when I press it.
void refreshStatusBar()
{
this.Title= "Holaaa";
}
WPF class:
<Height=.... Title="Prueba"...> the initial value
The problem is when I press a button (next or back) I need to set the Title of the page and never change when I call to refreshStatusBar() in the btNext or btBack method.
I tryed to binding the Title, but don´t work. Always show the same value, the initial:
Title="{Binding Path="windowTitleBar"}"
public String windowTitleBar {get; set;}
void refreshStatusBar(){
windowTitleBar="Holaaa";
}
I want the title change when I press some button. I don´t have pages inside the window page, just show one thing or another thing.
I tryed too:
Title="{Binding Path=windowTitleBar, RelativeSource={RelativeSource Mode=Self}}"
and don´t work neither.
Please, any solution to fix it?
Sorry for my english !
Thanks !
This works for me without a binding:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.Title = "Hellooo";
}
void RefreshStatusBar()
{
this.Title = "Holaaa";
}
private void button1_Click(object sender, RoutedEventArgs e)
{
RefreshStatusBar();
}
}
If you want to use a binding, set it up like you did with Title="{Binding Path=WindowTitleBar, RelativeSource={RelativeSource Mode=Self}}"
But as it is, WPF has no way of knowing when your property value changes. You can implement INotifyPropertyChanged to solve this:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string _windowTitleBar = "Hellooo";
public MainWindow()
{
this.WindowTitleBar = "Hellooo";
InitializeComponent();
}
public string WindowTitleBar
{
get { return _windowTitleBar; }
set
{
_windowTitleBar = value;
OnPropertyChanged("WindowTitleBar");
}
}
void RefreshStatusBar()
{
this.WindowTitleBar = "Holaaa";
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private void button1_Click(object sender, RoutedEventArgs e)
{
RefreshStatusBar();
}
}
Edit:
I just noticed you said "Page". I've never used Pages, but it looks like to set the title of the window containing your page, you have to set the WindowTitle property. Unfortunately it's not a DependencyProperty so you can't use a binding. You can set it directly, though:
void RefreshStatusBar()
{
this.WindowTitle = "Holaaa";
}
I ran into a quite confusing problem when developing a multi-window wpf application.
There are two windows, MainWindow and SecondWindow. The code of both is pretty simple:
MainWindow:
<Button Content="Change Property to 5" Click="ChangeProperty" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" />
SecondWindow:
<Label Content="{Binding InstanceOfMyClass.value, NotifyOnSourceUpdated=True}"></Label>
The code behind the second Window is untouched, the code behind the first window is the following:
public partial class MainWindow : Window
{
SecondWindow w;
ViewModel vm;
public MainWindow()
{
InitializeComponent();
vm = new ViewModel() { InstanceOfMyClass = new MyClass() { value = 3 } };
w = new SecondWindow() { DataContext = vm };
w.Show();
}
private void ChangeProperty(object sender, RoutedEventArgs e)
{
vm.InstanceOfMyClass.value = 7;
}
}
And the view model class which implements INotifyPropertyChanged:
class ViewModel : INotifyPropertyChanged
{
private MyClass _instance;
public MyClass InstanceOfMyClass
{
get
{
return _instance;
}
set
{
_instance = value;
OnPropertyChanged("InstanceOfMyClass");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
class MyClass
{
public int value { get; set; }
}
I expected the text block to change its text to 5 when I click the button.
The number "3" is correctly loaded on startup. The window also refreshes when I create a new instance of MyClass and set it as InstanceOfMyClass in my ViewModel.
But when I hit the button - or, even stranger, when I temporarily store InstanceOfMyClass, set it to null and reassign it with the saved variable - nothing happens.
Any idea why?
Thanks in advance!
Implement INotifyPropertyChanged in MyClass and try again. In ChangeProperty you change the value property, that doesn't notify the view about the change.
Or you can also try rewriting your ChangeProperty to the following:
vm.InstanceOfMyClass = new MyClass() { value = 7 };
Both of these approaches should fix the problem as far as I can see.
I have a button like this:
<Button Content="Gönder" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="932,23,0,0" Height="25" Command="{Binding Path=SetTeamList}" CommandParameter="{Binding ElementName=UrlBox, Path=Text}"/>
And at the VM, i have a method
public void SetTeamList(string Url)
{
//Some things here
}
The solution is WinForms app, so i set DataContext like this:
var view = new dTeamMapperForm();
view.DataContext = new TeamMappingVM();
elementHost1.Child = view;
Nothing happens when i click the button, no error or something. I put break point to SetTeamList method and it's not executing on button click.
Edit: I have changed the whole VM, now it looks like:
class TeamMappingVM : INotifyPropertyChanged
{
public ObservableCollection<Team> TeamList { get; set; }
public ICommand SetTeamsCommand { get; internal set; }
private string _url;
public string Url
{
get { return _url; }
set
{
_url = value;
NotifyPropertyChanged("Url");
}
}
public void SetTeamList()
{
var mapper = new TeamMapper();
TeamList = new ObservableCollection<Team>(mapper.MapTeams(Url));
}
public bool CanParseTeams()
{
return !string.IsNullOrEmpty(Url);
}
public TeamMappingVM()
{
SetTeamsCommand = new RelayCommand(SetTeamList, CanParseTeams);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
The Command-Property of a Button expects you to Bind to an Property of type ICommand.
In your Case you tried to Bind to a method, which does not work.
Since you edited you post i will just post this as the answer:
XAML:
<Button Content="Gönder" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="932,23,0,0" Height="25" Command="{Binding Path=SetTeamsCommand }" CommandParameter="{Binding ElementName=UrlBox, Path=Text}"/>
class TeamMappingVM : INotifyPropertyChanged
{
public ObservableCollection<Team> TeamList { get; set; }
public ICommand SetTeamsCommand { get; internal set; }
private string _url;
public string Url
{
get { return _url; }
set
{
_url = value;
NotifyPropertyChanged("Url");
}
}
public void SetTeamList()
{
var mapper = new TeamMapper();
TeamList = new ObservableCollection<Team>(mapper.MapTeams(Url));
}
public bool CanParseTeams()
{
return !string.IsNullOrEmpty(Url);
}
public TeamMappingVM()
{
SetTeamsCommand = new RelayCommand(SetTeamList, CanParseTeams);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
As a minor side note. Which was not asked. Since you are probably Using Databinding for your URL Textbox you don't need to pass it into the method via CommandParameter, Since the URL Property of your ViewMOdel represents this textbox. You want to try to seperate the view from the logic. This is a very small issue and might not have any effect, but it sort of is a bad habit to fall into.
As Xeun pointed out, a Command is not a method but an object implementing the ICommand interface. A Command implementation look like this:
class MyCommand: ICommand
{
public bool CanExecute(object parameter)
{
return true; // if your command is "enabled" otherwhise return false
}
public void Execute(object parameter)
{
// do something usefull
}
}
In this sample you should add an instance of MyCommand to your ViewModel an
bind to it.
Please notice usually you dont code commands this way.
A command usually interact with your ViewModel (ie it invokes Model methods) and inside MyCommand you have not references to the ViewModel hosting it.
(You could create a Command which hold a reference to its ViewModel, but...) Usually inside a ViewModel you use a Relay command or a Delegate command (which are basically the same thing).
Hi I am beginner using C# trying to produce a WPF(MVVM).
I have currently a TextBox & a ComboBox on a Window Form.
At the moment, I would like to arrange such that when user input an Access DB file path into the TextBox, the ComboBox will be automatically updated such that its available Items is the Tables Name in the MDB file. When user changed the MDB file path to another, ComboBox Items will be refreshed as well.
I have already prepared below Properties in the GUI's ViewModel.
...
public string MdbDir { get{;} set {; RaisePropertyChanged("MdbDir");} }
public List<string> MdbTblList { get{;} set{...; RaisePropertyChanged("MdbTblList");}}
...
I have already prepared below method in the Model.
...
public List<string> ReturnMdbTblList(string mdbDir)
{
List<string> mdbTblList = new List<string>();
oCat = new ADOX.Catalog();
oCat.ActiveConnection = oConn;
foreach (ADOX.Table oTable in oCat.Tables)
{
mdbTblList.Add(oTable.Name);
}
return mdbTblList;
}
...
I have already prepared below in View.xaml
...
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding MdbDir}" />
<ComboBox Grid.Column="1" Grid.Row="3" SelectedItem="{Binding Path=SelectedMdbTbl,Mode=TwoWay}" ItemsSource="{Binding MdbTblList}"/>
...
All I don't know is how to link the Model Method to ViewModel, and to make the ComboBox aware of MdbDir changed.
Any idea on what else to add the coding and at the same time minimize the amendment on the current piece of coding?
Thanks very much in advance :)
You can do that in two ways.
When ever you type the path in textBox and press tab, the Set part of the property MdbDir will be called. So you can call method like below. And in that method method you can fetch the details from the Model and update it to the UI.
public string MdbDir
{
get
{
;
} set
{
;
RaisePropertyChanged("MdbDir");
UpDateTheList()
}
}
Or you can have button on the UI and click of that can do the same thing. to Bind commands to buttons you can refer the below links
http://theprofessionalspoint.blogspot.in/2013/04/icommand-interface-and-relaycommand.html
http://www.codeproject.com/Articles/126249/MVVM-Pattern-in-WPF-A-Simple-Tutorial-for-Absolute
One more observation, if your new creating list every time then List is fine, but if your adding or removing something with already existing list then it'll not work for you, you have to use observablecollection instead of list
It is acceptable for your ViewModel to maintain a reference to your Model as the ViewModel can be thought of as a wrapper for your Model.
You could put a call to your Model method ReturnMdbTblList such as:
public string MdbDir
{
get
{
return this.mdbDir;
}
set
{
this.mdbDir = value;
RaisePropertyChanged("MdbDir");
this.MdbTblList = this.model.ReturnMdbTblList(value);
}
}
This is straight forward to implement and effective. My personal preference is not put anything inside the get and set methods of properties that do not directly affect the field it is accessing or notifying others it has changed. That is just my preference though, others may be happy to do so and I am not saying it is wrong.
I would use a DelegateCommand on the button to make the call to your ReturnMdbTdlList:
Model, ViewMode & DelegateCommand
public class MyViewModel : INotifyPropertyChanged
{
private readonly MyModel model;
private string mdbDir;
public string MdbDir
{
get
{
return this.mdbDir;
}
set
{
this.mdbDir = value;
RaisePropertyChanged("MdbDir");
}
}
private List<string> mdbTblList;
public List<string> MdbTblList
{
get
{
return this.mdbTblList;
}
set
{
this.mdbTblList = value;
RaisePropertyChanged("MdbTblList");
}
}
private DelegateCommand updateMdbTblListCommand;
public ICommand UpdateMdbTblListCommand
{
get
{
return this.updateMdbTblListCommand ??
(this.updateMdbTblListCommand = new DelegateCommand(this.UpdateMdbTblList));
}
}
public MyViewModel()
{
// This would idealy be injected via the constructor
this.model = new MyModel();
}
private void UpdateMdbTblList(object obj)
{
var param = obj as string;
this.MdbTblList = this.model.ReturnMdbTblList(param);
}
#region [ INotifyPropertyChanged ]
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
public class MyModel
{
public List<string> ReturnMdbTblList(string mdbDir)
{
// Do soemthing
return new List<string>();
}
}
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute,
Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this._canExecute == null || this._canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
XAML
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<TextBox Height="23" Margin="10" Width="200" Text="{Binding MdbDir}" />
<Button Content="Click Me" Width="100" Height="25" Margin="10" Command="{Binding Path=UpdateMdbTblListCommand}" CommandParameter="{Binding Path=MdbDir}" />
</StackPanel>
We bind the Command property of the Button to our UpdateMdbTblCommand in the MyViewModel, we also bind the CommandParameter property of the Button to the MdbDir property of MyViewModel. When the Button is pressed the UpdateMdbTblCommand is executed which in turn calls the UpdateMdbTbl passing along the value of MdbDir as an argument and subsequently updating the MdbTblList property of MyViewModel.
As I said the DelegateCommand would be my preferred method, however, it may be overkill when taking into consideration what you have to write to achieve what can be done in the former example.