Changing Grid Background Image of MainWindow from another Window's button - WPF - c#

Iam trying to change the image of the MainWindow's Grid, which is a room with no lights, by pressing a button on another Window, and come up with a room with lights background. The problem is that when i edit the onClick event of the button i cant change the MainWindow's Grid Background.
XAML of MainWindow's Grid:
<Grid x:Name="PIC">
<Grid.Background>
<ImageBrush ImageSource="lightsofflaptop.jpg"/>
</Grid.Background>
And the Window's Code:
public partial class Window3 : Window
{
public Window3()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
ImageBrush b1 = new ImageBrush();
b1.ImageSource = new BitmapImage(new Uri(#"---\lightsonNOlaptop.jpg"));
}
}
i cant connect b1 with the Grid Background of the MainWindow.
Thanks in advance.
**Edit
I navigate through Windows by this:
*button located in MainWindow.cs
private void button_Click(object sender, RoutedEventArgs e)
{
var newForm = new Window1();
newForm.Show();
this.Close();
}

It appears that you are a novice to WPF.
I would make a ViewModel and use this ViewModel in both Windows, and set the background property in Window3 and it will get reflected in MainWindow by Binding.
ViewModel
using System.ComponentModel;
using System.Windows.Media;
namespace WpfDatabase
{
public class ViewModel:INotifyPropertyChanged
{
private ImageBrush _background;
public ImageBrush Background
{
get { return _background; }
set { _background = value; OnPropertyChanged("Background"); }
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void OnPropertyChanged(string prop)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
MainWindow.xaml
<Grid Background="{Binding Background}">
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public ViewModel VM
{
get { return this.DataContext as ViewModel; }
set { this.DataContext = value; }
}
public MainWindow()
{
this.VM = new ViewModel();
InitializeComponent();
this.VM.Background = new ImageBrush(new BitmapImage(new Uri(#"C:\Users\Public\Pictures\Sample Pictures\Koala.jpg")));
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Window3 win = new Window3(VM);
win.Owner = this;
win.Show();
}
}
Window3
public partial class Window3 : Window
{
public ViewModel VM
{
get { return this.DataContext as ViewModel; }
set { this.DataContext = value; }
}
public Window1(ViewModel vm)
{
InitializeComponent();
VM = vm;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.VM.Background = new ImageBrush(new BitmapImage(new Uri(#"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg")));
}
}
See this

If you are opening Window3 from the Window with the Grid that needs the image changed, you could pass a reference of the grid window in the constructor
Like this:
(In Window 3 Code)
private Window1 _parentWindow = null;
public Window3(Window1 parent)
{
_parentWindow = parent;
InitializeComponents();
}
private void button_Click(object sender, RoutedEventArgs e)
{
ImageBrush b1 = new ImageBrush();
b1.ImageSource = new BitmapImage(new Uri(#"---\lightsonNOlaptop.jpg"));
_parentWindow.PIC.Background = b1;
}

You could get a reference to the MainWindow using the Application.Current.Windows property.
You also need to make the "PIC" Grid field internal or public to be able to access it from another window. The easiest way to do this is to set the x:FieldModifier attribute in the XAML markup.
Try this:
MainWindow.xaml:
<Grid x:Name="PIC" x:FieldModifier="public">
<Grid.Background>
<ImageBrush ImageSource="lightsofflaptop.jpg"/>
</Grid.Background>
...
Window3.xaml.cs:
private void button_Click(object sender, RoutedEventArgs e)
{
ImageBrush b1 = new ImageBrush();
b1.ImageSource = new BitmapImage(new Uri(#"---\lightsonNOlaptop.jpg"));
MainWindow mw = Application.Current.Windows.OfType<MainWindow>().FirstOrDefault();
if(mw != null)
mw.PIC.Backgound = b1;
}

Related

WPF Command Binding on Code Behind problem

I am new to WPF and I have created a WPF Application. In that application, I have a UserControl that contain a button as below,
<UserControl.DataContext>
<local:AppViewModel/>
</UserControl.DataContext>
<Grid>
<Button x:Name="Btn_Contact" Command="{Binding BookVM.LoadContactsCommand}" Click="Btn_Contact_Click"/>
</Grid>
And My AppViewModel Class is as below
public AppViewModel()
{
var dataService = new JsonContactDataService();
BookVM = new BookViewModel(dataService);
CurrentView = BookVM;
}
My problem is I want this UserControl to run command of the Btn_Contact automatically when the UserControl is loaded instead of clicking the button. I have try to write the command binding on the UserControl code-behind but it does not worked.
public UserControlMemo()
{
InitializeComponent();
Btn_Contact.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
Btn_Contact.SetBinding(Button.CommandProperty, new Binding("BookVM.LoadContactsCommand"));
}
In its simplest form:
public UserControlMemo()
{
Loaded += OnLoaded;
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (DataContext is AppViewModel viewModel)
viewModel.BookVM.LoadContactsCommand.Execute(null);
}

Unable to get values from pop up window in parent view model WPF MVVM application

I am trying to access property value of a child window's view model from the parent View Model.I am calling window from parent view model.I want to make changes in main window based on the operation in child view model. I couldn't get any value of child view model in parent view model.I am trying this in MVVM pattern.
Interface for dialog
public interface IWindowService
{
void OpenDialogWindow(DialogViewModel vm);
}
Parent view model
public class FunctionalViewModel : INotifyPropertyChanged
{
private readonly IWindowService _windowService;
private string connectionString;
public string ConnectionString
{
get { return connectionString; }
set
{
connectionString = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ConnectionString"));
}
}
public FunctionalViewModel(IWindowService windowService)
{
BuildConnectionCommand = new RelayCommand(new Action<object>(BuildConnectionString));
_windowService = windowService;
}
private void BuildConnectionString(object obj)
{
MessageBox.Show("will open a window");
_windowService.OpenDialogWindow(new DialogViewModel());
}
}
Child View Model
public class DialogViewModel : FunctionalViewModel,INotifyPropertyChanged
{
private string textboxsaf;
public string Textboxsaf
{
get { return textboxsaf; }
set {
textboxsaf = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Textboxsaf"));
}
}
private ICommand connectionCommand;
public ICommand ConnectionCommand
{
get { return connectionCommand; }
set { connectionCommand = value; }
}
public DialogViewModel()
{
ConnectionCommand = new RelayCommand(new Action<object>(SetValue));
}
public event PropertyChangedEventHandler PropertyChanged;
public void SetValue(object test)
{
textboxsaf= "ValueFromPopUpWindo";
Application.Current.Windows[1].Close();
}
}
ChildWindow.xaml
<Grid>
<Label x:Name="label" Content="my popup window" HorizontalAlignment="Left" Margin="73,68,0,0" VerticalAlignment="Top" Width="132"/>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="73,121,0,0"
TextWrapping="Wrap"
Text="{Binding Path=Textboxsaf,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left"
Margin="109,177,0,0" VerticalAlignment="Top" Width="75"
Command="{Binding Path=ConnectionCommand }"
/>
</Grid>
</Window>
MainWindow.xaml
<Grid>
<Button Name="btnConnectionString" Grid.Row="0" Grid.Column="2" Content="Connection string" Height="40" Width="150"
Command="{Binding Path=BuildConnectionCommand}"
DataContext="{Binding tfs}"></Button>
</Grid>
Code behind file of main window
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel()
{
rel = new ReleaseViewModel(),
tfs = new FunctionalViewModel(new WindowService()),
wnd = new DialogViewModel()
};
}
}
public class WindowService : IWindowService
{
public void OpenDialogWindow(DialogViewModel vm)
{
ConnectionWindow win = new ConnectionWindow();
win.DataContext = vm;
win.Show();
}
}
Question
I would like to access the value of the property Textboxsaf in the child view model(DialogViewModel) from parent view model(FunctionalViewModel) . Assign value of Textboxsaf to ConnectionString from the funcitonalviewModel . after closing window is good.
I wouldn't use PropertyChanged to retrieve the value of DialogViewModel.Textboxsaf as this proprty might change multiple times during the lifetime of the dialog.
I would make IWindowService.OpenDialogWindow return a custom DialogResult object or the original DialogViewModel probably converting the IWindowService.OpenDialogWindow to an asynchronous method.
Alternatively implement a IWindowService.DialogClosed event:
FunctionalViewModel.cs
public class FunctionalViewModel : INotifyPropertyChanged
{
private readonly IWindowService _windowService;
private string connectionString;
public string ConnectionString
{
get { return connectionString; }
set
{
connectionString = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.ConnectionString)));
}
}
private void BuildConnectionString(object obj)
{
MessageBox.Show("will open a window");
_windowService.DialogClosed += OnDialogClosed;
_windowService.OpenDialogWindow(new DialogViewModel());
}
private void OnDialogClosed(object sender, DialogResultEventArgs e)
{
_windowService.DialogClosed -= OnDialogClosed;
ConnectionString = e.Result.Textboxsaf;
}
}
WindowService.cs
public class WindowService : IWindowService
{
public event EventHandler<DialogResultEventArgs> DialogClosed;
public void OpenDialogWindow(DialogViewModel vm)
{
ConnectionWindow win = new ConnectionWindow();
win.DataContext = vm;
win.Closed += OnConnectionWindowClosed;
win.Show();
}
protected virtual void OnConnectionWindowClosed(object sender, EventArgs e)
{
var dialog = sender as FrameworkElement;
this.DialogClosed?.Invoke(this, new DialogResultEventArgs(dialog.DataContext as DialogViewModel));
}
}
DialogResultEventArgs.cs
public class DialogResultEventArgs : EventArgs
{
public DialogViewModel Result { get; }
public DialogResultEventArgs(DialogViewModel result) => this.Result = result;
}
You could keep a reference to the DialogViewModel and subscribe to its PropertyChanged event:
private void BuildConnectionString(object obj)
{
var childViewModel = new DialogViewModel();
childViewModel.PropertyChanged += OnChildPropertyChanged;
MessageBox.Show("will open a window");
_windowService.OpenDialogWindow(childViewModel);
}
private void OnChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(DialogViewModel.Textboxsaf))
{
childViewModel.PropertyChanged -= OnChildPropertyChanged;
ConnectionString = (sender as DialogViewModel)?.DialogViewModel;
}
}

How to send TextBox value from modal window to main window programmatically?

I'm trying to learn WPF MVVM I would need to understand how to update a textbox value via a modal window. Below the code, I wrote passes the value to the viewmodel but does not update the textbox. Thanks in advance
UserControl con il TextBox
<TextBox x:Name="Text01UC" Text="{Binding TextUC, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Width="200" Height="33"/>
UserControl Behind
namespace InvioDati
{
public partial class textbox : UserControl
{
public textbox()
{
InitializeComponent();
var vm = new ModelTextView();
this.DataContext = vm;
vm.Load();
}
private void Open_Click(object sender, RoutedEventArgs e)
{
MoadalWindow md = new MoadalWindow();
md.ShowDialog();
}
}
}
ModelTextView
namespace InvioDati
{
class ModelTextView : BaseViewModel
{
private ModelText dati = new ModelText();
public string TextUC
{
get => dati.TextVal;
set
{
dati.TextVal = value;
OnPropertyChanged();
}
}
public void Load() {
TextUC = "GoodMorning";
}
public void Ricevi(string valore)
{
TextUC = valore;
}
}
}
ModalWindow Code behind
namespace InvioDati
{
public partial class MoadalWindow : Window
{
public MoadalWindow()
{
InitializeComponent();
}
private void Test_Click(object sender, RoutedEventArgs e)
{
ModelTextView nd = new ModelTextView();
nd.Ricevi(Send.Text);
this.Close();
}
}
}
Set the DataContext of the ModalWindow to the same instance of ModelTextView in textbox.xaml.cs:
private void Open_Click(object sender, RoutedEventArgs e)
{
MoadalWindow md = new MoadalWindow();
md.DataContext = this.DataContext;
md.ShowDialog();
}
You can then either bind directly to the TextUC property or do the following in ModalWindow.xaml.cs:
private void Test_Click(object sender, RoutedEventArgs e)
{
ModelTextView nd = DataContext as ModelTextView;
nd.Ricevi(Send.Text);
this.Close();
}
You must use a mediator in order not to break mvvm here.
Check https://en.wikipedia.org/wiki/Mediator_pattern#C#
1b. Add Observer pattern to create notifications for value changes.
Dialogs are evil within MVVM, usually you won't need them. What you want is an overlaying View, which can be Data bound in any way as there is no break in the visual tree
If you want to use "dialogs", implement a DialogService to do so.
Edit: here is a draft on how you create something "popup" like in the most simple way:
<UserControl>
<Grid>
<!--Invert visability of all controls below via binding-->
<YourMainControl/>
<Rect Fill="Black" Opacity=".5 Visibility="Hidden"/>
<YourSubControl Visibility="Hidden"/>
</Grid>
</UserControl>

WPF UserControl property change not updating

I have a UserControl that I add to my main application.
That UserControl contains a button for a UIElement
The UserControl contains a DispatchTimer and every 2 seconds based on some int values determines what the button image will be.
One of the methods called in the UserControl should set it's image but the control never displays the image that it was changed to.
public void SetNormal()
{
btnFlashAlert.Content = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute));
}
Is there something i'm missing to get the look of the control update on the main application?
When I look at what .Content contains, it is correct. The UI doesn't reflect the change.
XAML
<UserControl x:Class="SC.FlashSystem.MainButton"
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"
mc:Ignorable="d" Height="53" Width="164">
<Button x:Name="btnFlashAlert" Background="{x:Null}" BorderBrush="{x:Null}" Cursor="Hand" Click="btnFlashAlert_Click">
<Button.Template>
<ControlTemplate>
<Image Source="Images/FlashButton.png"/>
</ControlTemplate>
</Button.Template>
</Button>
Codebehind Updated
public partial class MainButton : UserControl
{
private SupportConsoleWeb.MessageData messageCounts { get; set; }
private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer();
private BitmapImage NormalImage { get; set; }
private BitmapImage CriticalImage { get; set; }
private BitmapImage AlertImage { get; set; }
private BitmapImage InfoImage { get; set; }
public MainButton()
{
InitializeComponent();
messageCounts = new SupportConsoleWeb.MessageData();
messageCounts.CriticalCount = 0;
messageCounts.AlertCount = 0;
messageCounts.InfoCount = 0;
NormalImage = new BitmapImage(new Uri("Images/FlashButton.png", UriKind.RelativeOrAbsolute));
CriticalImage = new BitmapImage(new Uri("Images/FlashButtonRed.png", UriKind.RelativeOrAbsolute));
AlertImage = new BitmapImage(new Uri("Images/FlashButtonOrange.png", UriKind.RelativeOrAbsolute));
InfoImage = new BitmapImage(new Uri("Images/FlashButtonGreen.png", UriKind.RelativeOrAbsolute));
flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2);
flashButtonChangeTimer.Tick += flashButtonChangeTimer_Tick;
flashButtonChangeTimer.Start();
}
void flashButtonChangeTimer_Tick(object sender, EventArgs e)
{
btnFlashAlert.Dispatcher.BeginInvoke(new Action(() =>
{
if (btnFlashAlert.Content == null)
{
SetNormal();
}
else if (messageCounts.CriticalCount > 0 && btnFlashAlert.Content.Equals(CriticalImage))
{
SetNormal();
}
else if (messageCounts.AlertCount > 0 && btnFlashAlert.Content.Equals(AlertImage))
{
SetNormal();
}
else if (messageCounts.InfoCount > 0 && btnFlashAlert.Content.Equals(InfoImage))
{
SetNormal();
}
else if (messageCounts.CriticalCount > 0)
{
SetCritical();
}
else if (messageCounts.AlertCount > 0)
{
SetAlert();
}
else if (messageCounts.InfoCount > 0)
{
SetInfo();
}
}));
}
public void UpdateMessageCounts(SupportConsoleWeb.MessageData messageCounts)
{
this.messageCounts = messageCounts;
}
private void btnFlashAlert_Click(object sender, RoutedEventArgs e)
{
MainWindow window = new MainWindow();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
window.ShowDialog();
}
public void SetMessageCount(int criticalCount, int alertCount, int infoCount)
{
messageCounts.CriticalCount = criticalCount;
messageCounts.AlertCount = alertCount;
messageCounts.InfoCount = infoCount;
}
private void SetNormal()
{
btnFlashAlert.Content = NormalImage;
}
private void SetCritical()
{
btnFlashAlert.Content = CriticalImage;
}
private void SetAlert()
{
btnFlashAlert.Content = AlertImage;
}
private void SetInfo()
{
btnFlashAlert.Content = InfoImage;
}
}
Change your XAML To this
<Image Source="{Binding TheImage}"/>
Add notify property changed
public partial class MainButton : UserControl, INotifyPropertyChanged
Create the OnPropertyChanged Event
void OnPropertyChanged(String prop)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
public event PropertyChangedEventHandler PropertyChanged;
Create a Bitmap prop and notify the prop changed event
private BitmapImage _TheImage;
public BitmapImage TheImage
{
get { return _TheImage; }
set { _TheImage = value; OnPropertyChanged("TheImage"); }
}
In your initializer
public MainButton()
{
this.DataContext = this;
InitializeComponent();
TheImage = new BitmapImage();
Now in your setting methods call
TheImage = //Your Bitmap Goes here
I know this seems excessive but you will see it is a much cleaner implementation in the long run.
I believe its an issue with picture selection logic not having a default image when none of the conditions are met...
With that said, IMHO the picture logic would be better expressed by having all images pre-loaded and their visibility initially set to hidden. Then bind the visibility of each image to a specific flag boolean on the VM. Which the timer event can simply turn on or off the boolean(s) which will ultimately show or hide images as needed.
That removes any latency due to loading and showing of images for they will be pre-loaded; also it will solve any possible future memory issues due to loading/unloading of images.
Example
The following example has a button with two images. Both image's visibility is bound to Booleans on the VM. The VM has one Boolean which the imageas work off of and a timer which changes its status every two seconds switching the images.
Xaml:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<Button x:Name="bStatus" Width="48" Height="48">
<StackPanel Orientation="Vertical">
<Image Source="Images\Copy-icon.png" Visibility="{Binding IsCopyOn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<Image Source="Images\Recycle-icon.png"
Visibility="{Binding IsRecycleOn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel>
</Button>
VM
public class MainVM : INotifyPropertyChanged
{
private bool _bSwitch;
private readonly DispatcherTimer flashButtonChangeTimer = new DispatcherTimer();
public bool IsRecycleOn
{
get { return _bSwitch; }
}
public bool IsCopyOn
{
get { return !_bSwitch; }
}
public MainVM()
{
flashButtonChangeTimer.Interval = TimeSpan.FromSeconds(2);
flashButtonChangeTimer.Tick += (sender, args) =>
{
_bSwitch = ! _bSwitch;
OnPropertyChanged("IsCopyOn");
OnPropertyChanged("IsRecycleOn");
};
flashButtonChangeTimer.Start();
}
/// <summary>Event raised when a property changes.</summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>Raises the PropertyChanged event.</summary>
/// <param name="propertyName">The name of the property that has changed.</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

ImageTools on Windows Phone 8, changing ImageSource and DataContext

I have problem with DataContext in Windows Phone 8 project. When I run project and MainPage() is done - I see 1st GIF, but when I go Button_Click_1 - 1st GIF is still visible. I have no idea how DataContext work. Is there any way to set DataContext again and display 2nd GIF?
namespace PhoneApp1
{
public partial class MainPage : PhoneApplicationPage
{
public Uri ImageSource { get; set; }
// Constructor
public MainPage()
{
InitializeComponent();
ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
ImageSource = new Uri("http://c.wrzuta.pl/wi7505/bcd026ca001736004fc76975/szczur-piwo-gif-gif", UriKind.Absolute);
this.DataContext = this;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ImageSource = new Uri("http://0-media-cdn.foolz.us/ffuuka/board/wsg/image/1338/94/1338947099997.gif", UriKind.Absolute);
this.DataContext = this;
}
}
}
XAML
<imagetools:AnimatedImage x:Name="Image" Source="{Binding ImageSource, Converter={StaticResource ImageConverter}}" Margin="43,0,50,257" />
You will want to implement INotifyPropertyChanged so the Xaml knows of the changes to the ImageSource property.
Example:
public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
{
private Uri _imageSource;
public Uri ImageSource
{
get { return _imageSource; }
set { _imageSource = value; NotifyPropertyChanged("ImageSource"); }
}
// Constructor
public MainPage()
{
InitializeComponent();
ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
this.DataContext = this;
ImageSource = new Uri("http://c.wrzuta.pl/wi7505/bcd026ca001736004fc76975/szczur-piwo-gif-gif", UriKind.Absolute);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ImageSource = new Uri("http://0-media-cdn.foolz.us/ffuuka/board/wsg/image/1338/94/1338947099997.gif", UriKind.Absolute);
}
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notifies the property changed.
/// </summary>
/// <param name="property">The property.</param>
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}

Categories