Freezing main window after adding some items from childwindow - c#

I am working on Silverlight 4 with mvvm and WCF services.
Whenever I am adding items from child window to main window. But at the same time main window automatically going to disabling mode. I think main window automatically freezes.
ChildWindow ViewModel
public class AddFormFieldInformationViewModel : ViewModelBase
{
private FieldInformationViewModel _FieldInformationViewModel;
public FieldInformationViewModel FieldInformationViewModel
{
get { return _FieldInformationViewModel; }
set
{
_FieldInformationViewModel = value;
RaisePropertyChanged("FieldInformationViewModel");
}
}
public void MoveSave(object obj)
{ this.FieldInformationViewModel.SelectedFormFields = FieldInformationModel;
ResultHandler(true);
}
public Action ResultHandler { get; set; }
}
ChildWindow .xaml.cs file
public partial class AddExistingFormFieldCategoryView : ChildWindow
{
private AddFormFieldInformationViewModel vm;
public AddExistingFormFieldCategoryView()
{
InitializeComponent();
vm = new AddFormFieldInformationViewModel();
this.DataContext = vm;
vm.ResultHandler = result => { if (result) { Close(); } };
}
}
Main Window ViewModel
public class FieldInformationViewModel : ViewModelBase
{ private void executeOpenChildWindow(object parameter)
{
AddExistingFormFieldCategoryView cw = new AddExistingFormFieldCategoryView();
((AddFormFieldInformationViewModel)cw.DataContext).FieldInformationViewModel = this;
cw.Show();
}
}
After adding items from child window into main window, sometimes my main window is automatically freezing.

Hi this is a bug you are experiencing see the sample below. I the same issue and you have to manually enable the display of the main page:
private static void ShowError(string message, string details)
{
ErrorWindow error = new ErrorWindow(message, details);
error.Closed += new EventHandler(error_Closed);
error.Show();
}
static void error_Closed(object sender, EventArgs e)
{
Application.Current.RootVisual.SetValue(Control.IsEnabledProperty, true);
}

You can subclass the ChildWindow and explicitly set the RootVisual to enabled. Source
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace DST_Common_Silverlight_Controls
{
/// <summary>
/// Bug in ChildWindow sometimes leaves app disabled.
/// </summary>
public class ChildWindowEx : ChildWindow
{
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Application.Current.RootVisual.SetValue(Control.IsEnabledProperty, true);
}
}
}
Then just use the new type instead of ChildWindow in xaml like this:
<slcommon:ChildWindowEx
x:Class="DST.AvSyncMonitor.Silverlight.Gui.ErrorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:slcommon="clr-namespace:DST_Common_Silverlight_Controls;assembly=DST.Common.Silverlight.Controls"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
Title="Error">
<Grid x:Name="LayoutRoot" Width="540">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="IntroductoryText" Grid.Row="0" Margin="0"
Text="An unknown error was encountered. Please contact your administrator for more information."/>
<StackPanel x:Name="ContentStackPanel" Grid.Row="2" Margin="0,6,0,0">
<TextBlock x:Name="LabelText" TextWrapping="Wrap" Margin="0,0,0,2"
Text="Error details"/>
<TextBox x:Name="ErrorTextBox" Height="90" TextWrapping="Wrap" IsReadOnly="True"
VerticalScrollBarVisibility="Auto"/>
</StackPanel>
<Button x:Name="OKButton" Grid.Row="3" Click="OKButton_Click"
Width="75" Height="23" HorizontalAlignment="Right" Margin="0,10,0,0"
TabIndex="0" Content="OK"/>
</Grid>
</slcommon:ChildWindowEx>

Related

How to edit an observableCollection while WPF app is running

I am making a To-do List application for one of my classes. Now I have tried in a console app to update objects (of TaskModels a type I defined) inside an observable collection and it has seemed to work. But now I am trying to update the entries inside the observable collection. I have wrote some code that I thought was going to change the value but it did not change the value in the ListBox I will include the code below for TaskModel.
Originally I was wanting to have the edit button open a new window that allowed the user to input what the wanted the task to be and then they press a button maybe called change task and it sends it back to the original window. But for simpleness at the moment I would like to change with the textbox in the user control in the main window.
I am also pretty new to making apps in WPF so this is all pretty new to me and I am trying to learn it all.
Below is my TaskModel and the only thing it does is get and set the TaskName.
namespace ToDoList.Model
{
public class TaskModel
{
private string taskName;
public string TaskName {
get { return taskName; }
set { taskName = value; }
}
}
}
I wrote the following code hoping that it would allow me to change the value of the TaskName but it does not seem to be working. Is there anyhting else that I should add to the code for it change the TaskName properly? Any tips or anything that could help me with this problem.
Below is the XAML code for my main window. It is a really simple UI, it features a ListBox which uses an ObservableCollection as its itemsource and when the listbox has a new item put into it has a checkbox to the left of it.
Below I will include the main window XAML and the C# code.
<Window x:Class="ToDoList.DemoMainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ToDoList"
mc:Ignorable="d"
Title="The To-Do List" Height="500" Width="500" FontSize="22"
Background="White">
<Grid Margin="10" Background="BlueViolet">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock>Tasks to do:</TextBlock>
<!-- <TextBlock>Blah blah</TextBlock> -->
<!-- <local:UCLabelTextBxInput x:Name="TxtUCSaveToFileLocation" Title="Save to File Location" MaxLength="50"></local:UCLabelTextBxInput> -->
<ListBox x:Name="LstBoxTasks" MinHeight="200" MaxHeight="200" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Mode=OneWay}" Content="{Binding TaskName, Mode=TwoWay}" FontSize="14"></CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<local:UCLabelTextBxInput x:Name="TxtUCEnteredTask" Title="Enter Task Here:" MaxLength="50"></local:UCLabelTextBxInput>
<Button x:Name="BtnAddTask" Click="BtnAddTask_Click" Background="Chocolate">Add Task to List</Button>
</StackPanel>
<Button Grid.Column="0" Grid.Row="1" Margin="0,10,20,0" x:Name="btnDeleteTask" Click="BtnDeleteTask_Click" Background="Chocolate">Delete Task</Button>
<Button Grid.Column="1" Grid.Row="1" Margin="20,10,0,0" Background="Chocolate" Click="BtnEditTask_Click">Edit Task</Button>
<Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,10" Grid.ColumnSpan="2" Background="Chocolate" Click="BtnHelp_Click">Help</Button>
</Grid>
</Window>
Then finally here is the C# code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ToDoList.Model;
namespace ToDoList
{
/// <summary>
/// Interaction logic for DemoMainWindow.xaml
/// </summary>
public partial class DemoMainWindow : Window
{
SaveDataModel saveDataModel = new SaveDataModel();
ObservableCollection<TaskModel> tasksModels = new ObservableCollection<TaskModel>();
public DemoMainWindow()
{
InitializeComponent();
TxtUCEnteredTask.txtLimitedInput.Text = "Do the dishes";
LstBoxTasks.ItemsSource = tasksModels;
}
private void BtnAddTask_Click(object sender, RoutedEventArgs e)
{
tasksModels.Add(new TaskModel() { TaskName = TxtUCEnteredTask.txtLimitedInput.Text });
}
private void BtnDeleteTask_Click(object sender, RoutedEventArgs e)
{
if(LstBoxTasks.SelectedItem != null)
{
tasksModels.Remove(LstBoxTasks.SelectedItem as TaskModel);
}
}
private void BtnHelp_Click(object sender, RoutedEventArgs e)
{
HelpWindow helpWindow = new HelpWindow();
helpWindow.Show();
}
private void BtnEditTask_Click(object sender, RoutedEventArgs e)
{
if (LstBoxTasks.SelectedItem != null)
{
tasksModels[LstBoxTasks.SelectedIndex].TaskName = TxtUCEnteredTask.txtLimitedInput.Text;
}
}
}
}
Your property TaskName is not calling the OnPropertyChanged() method that notifies your view that the name changed.
You can do something like that:
private string taskName;
public string TaskName {
get { return taskName; }
set {
if( value != taskName) {
taskName = value;
OnPropertyChanged("TaskName");
}
}
}
protected void OnPropertyChanged(string name) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
Remarks:
The best way to do WPF is to do MVVM.
You should check out this link : https://www.codeproject.com/Tips/806587/Basic-MVVM-Listbox-Binding-in-WPF

WPF MVVM ErrorCode: CS1061

- the red markups are for Inputs(xAxis and yAxis)
- after i press the button (Calculate), the inputs should be calculated.
- then outputed at the blue markup(texbox called Output)
After i made some kata with element binding, i just wanted to
start MVVM property binding.
For some reason i get a ErrorCode: CS1061
Error CS1061 MainWindow does not contain a definition for
CalculateClick and no extension method CalculateClick accepting a
first argument of type MainWindow could be found (are you missing a
using directive or an assembly reference?)
the weird part of this is when i use the resharper eventhandler on my MainWindow.xml at my button it creates a event in my MainWindow.cs.
But it didnt before. the events were autocreated in my ViewModel.cs
im not sure what causes this error
ty in advance when somone could help me, i have already been sitting on this kata for more then 8 hours.
Heres my MainWindow.xml:
<Window x:Class="Coordinates.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Coordinates"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Insert X-Coordiante"/>
<Label Grid.Row="0" Grid.Column="1" Content="Insert Y-Coordinate"/>
<TextBox Grid.Row="1" Grid.Column="0" Name="TxtXaxis" Text="{Binding Xaxis}"/>
<TextBox Grid.Row="1" Grid.Column="1" Name="TxtYaxis" Text="{Binding Xaxis}"/>
<TextBox Grid.Row="2" Grid.Column="0" Text="{Binding Output}"/>
<Button Grid.Row="2" Grid.Column="1" Name="Calculate" Click="CalculateClick">Calculate</Button>
</Grid>
This is my MainWinow.xml.cs:
using System.Windows;
namespace Coordinates
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.InitializeComponent();
this.DataContext = new ViewModel();
}
}
}
This is my ViewModel.cs:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace Coordinates
{
public class ViewModel : INotifyPropertyChanged
{
#region Inputs
private double _xaxis;
public double Xaxis
{
get => this._xaxis;
set
{
if (value == this._xaxis)
{
return;
}
this._xaxis = value;
this.OnPropertyChanged();
}
}
private double _yaxis;
public double Yaxis
{
get => this._yaxis;
set
{
if (value == this._yaxis)
{
return;
}
this._yaxis = value;
this.OnPropertyChanged();
}
}
#endregion
public void CalculateClick(object sender, RoutedEventArgs e)
{
Output = Math.Sqrt(Math.Pow(Xaxis,2)+Math.Pow(Yaxis,2));
}
private double _output;
public double Output
{
get => this._output;
set
{
if (value == this._output)
{
return;
}
this._output = value;
this.OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
EDIT: this was missing in CalculateClick in my viewmodel:
Output = Math.Sqrt(Math.Pow(Xaxis,2)+Math.Pow(Yaxis,2));
You are using a CalculateClick as Eventhandler for the Click Event of the Button.
Per Default, WPF looks in the Code Behind (MainWindow.cs) for the Eventhandler, which is not there.
Since you are already initializing your DataContext within the Code Behind. Make your ViewModel a private member of your MainWindow.
Create an event handler in the MainWindow Code Behind and call your event handler in the ViewModel from there.
public partial class MainWindow : Window
{
private _viewModel = new ViewModel();
public MainWindow()
{
InitializeComponent();
this.InitializeComponent();
this.DataContext = _viewModel;
}
}
public void CalculateClick(object sender, RoutedEventArgs e)
{
_viewModel.CalculateClick(Sender, e);
}
You might also want to look into Commands, which can be created directly inside of the ViewModel and then be bound to. There is an ActionCommand or GenericCommand, which take an Action or Action<T> and are pretty easy to use.

How to show a view using Catel

I am developing a simple app with Catel. I have previously used ReactiveUI and am having a little trouble getting started with Catel. I have a basic MainWindow. In there I have a toolbar with some buttons. When a button is selected I would like to show in the bottom pane of the application a user control (based on what they selected). So far I have one basic view that has a listview in it and then a view model behind it. I need help in figuring out how to show that view when the button is selected. Thank you for your help. Here is what I have so far. As you can see, when the 'ExecutePlayersButtonCommand' in the mainviewmodel is run, i want it to show the players view. I am not sure how to get this. I can get it to come up in a popup but that is not what i want. In reactiveui I can do it with the Router.Navigate function. Not sure how to do it here.
<catel:DataWindow xmlns:Controls="clr-namespace:FootballSim.Controls;assembly=FootballSim.Controls"
xmlns:RedfoxSoftwareCustomControls="clr-namespace:RedfoxSoftwareCustomControls;assembly=RedfoxSoftwareCustomControls"
x:Class="FootballSim.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"
xmlns:views="clr-namespace:FootballSim.Views"
Style="{StaticResource {x:Type Window}}"
ShowInTaskbar="True" ResizeMode="CanResize" SizeToContent="Manual"
WindowStartupLocation="Manual" WindowState="Maximized" Icon="/FootballSim;component/redfox_software_48x48.ico">
<!-- Resources -->
<catel:DataWindow.Resources>
</catel:DataWindow.Resources>
<!-- Content -->
<catel:StackGrid x:Name="LayoutRoot">
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>
<DockPanel>
<StackPanel DockPanel.Dock="Top">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
<RowDefinition Height="100*" />
</Grid.RowDefinitions>
<RedfoxSoftwareCustomControls:WpfCustomApplicationMenuBar x:Name="CustomMenuBar" Grid.Row="0" />
<StackPanel Grid.Row="1">
<Button HorizontalAlignment="Left" Command="{Binding PlayersButtonCommand}" Background="Transparent">
<StackPanel>
<Image Source="/FootballSim;component/Resources/People_white_48.png" Width="30"></Image>
<TextBlock Text="Players" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</StackPanel>
<DockPanel LastChildFill="True" Grid.Row="2">
<ContentControl Content="{Binding contentObject}" />
<!--<views:PlayersView DataContext="{Binding PlayerProviders}" />-->
</DockPanel>
</Grid>
</StackPanel>
</DockPanel>
</catel:StackGrid>
</catel:DataWindow>
using Catel.Windows;
using FootballSim.Scripts;
using FootballSim.Services;
using FootballSim.ViewModels;
using System;
using System.ComponentModel;
using Catel.MVVM.Views;
using Catel.Windows.Data;
using Catel.MVVM;
namespace FootballSim.Views
{
public partial class MainWindow : DataWindow
{
private RedfoxMessage logger = new RedfoxMessage();
private PopulateDatabase database = new PopulateDatabase();
public MainWindow() : base(DataWindowMode.Custom)
{
try
{
InitializeComponent();
logger.LogMessage("Starting application.");
CustomMenuBar.AboutButtonClickEvent += CustomMenuBar_AboutButtonClickEvent;
}
catch (Exception e)
{
RedfoxMessage.LogMessage(e, NLog.LogLevel.Error);
}
}
private void CustomMenuBar_AboutButtonClickEvent(object sender, System.EventArgs args)
{
(DataContext as IMainWindowViewModel).AboutButtonCommand.Execute(null);
}
}
}
using Catel.Data;
using Catel.IoC;
using Catel.MVVM;
using Catel.MVVM.Services;
using FootballSim.Models;
using FootballSim.Scripts;
using FootballSim.Views;
using System.Collections.Generic;
using System.Windows;
namespace FootballSim.ViewModels
{
public interface IMainWindowViewModel
{
Command PlayersButtonCommand { get; }
Command AboutButtonCommand { get; }
List<Player> PlayerProviders { get; }
Player SelectedPlayerProvider { get; }
object ContentObject { get; }
}
/// <summary>
/// MainWindow view model.
/// </summary>
public class MainWindowViewModel : ViewModelBase, IMainWindowViewModel
{
//private readonly IUIVisualizerService _uiVisualizerService;
private PopulateDatabase _populateDatabase;
public static readonly PropertyData PlayerProvidersProperty = RegisterProperty("PlayerProviders", typeof(List<Player>));
public static readonly PropertyData SelectedPlayerProviderProperty = RegisterProperty("SelectedPlayerProvider", typeof(Player));
public Command PlayersButtonCommand { get; private set; }
public Command AboutButtonCommand { get; private set; }
public object ContentObject { get; set; }
public MainWindowViewModel() : base()
{
//var dependencyResolver = this.GetDependencyResolver();
//_uiVisualizerService = dependencyResolver.Resolve<IUIVisualizerService>();
_populateDatabase = new PopulateDatabase();
PlayerProviders = _populateDatabase.Players;
var pv = new PlayersView();
pv.DataContext = PlayerProviders;
ContentObject = pv;
PlayersButtonCommand = new Command(ExecutePlayersButtonCommand);
AboutButtonCommand = new Command(ExecuteAboutButtonCommand);
}
private void ExecutePlayersButtonCommand()
{
PlayerProviders = _populateDatabase.Players;
MessageBox.Show("Players");
}
private void ExecuteAboutButtonCommand()
{
var aboutView = new AboutView();
aboutView.ShowDialog();
}
public List<Player> PlayerProviders
{
get
{
return GetValue<List<Player>>(PlayerProvidersProperty);
}
set
{
SetValue(PlayerProvidersProperty, value);
}
}
public Player SelectedPlayerProvider
{
get
{
return GetValue<Player>(SelectedPlayerProviderProperty);
}
set
{
SetValue(SelectedPlayerProviderProperty, value);
}
}
//protected override void Initialize()
//{
// SelectedPlayerProvider = PlayerProviders[0];
//}
public override string Title { get { return "FootballSim"; } }
}
}
<catel:UserControl x:Class="FootballSim.Views.PlayersView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"
xmlns:views="clr-namespace:FootballSim.Views"
xmlns:viewmodels="clr-namespace:FootballSim.ViewModels"
xmlns:models="clr-namespace:FootballSim.Models;assembly=FootballSim.Core">
<!-- Resources -->
<UserControl.Resources>
</UserControl.Resources>
<!-- Content -->
<catel:StackGrid>
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>
<Label Content="{Binding Title}" Foreground="White" Grid.Row="0" />
<Label Content="Here goes your real content" Foreground="White" Grid.Row="1"/>
<ListBox Grid.Row="2" ItemsSource="{Binding PlayersCollection}" SelectedItem="{Binding SelectedPlayer}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding ColumnValue}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!--<views:PlayersView Grid.Column="1" DataContext="{Binding SelectedPlayer}" />-->
</catel:StackGrid>
</catel:UserControl>
namespace FootballSim.Views
{
using Catel.Windows.Controls;
using FootballSim.ViewModels;
public partial class PlayersView : UserControl
{
public PlayersView()
{
InitializeComponent();
}
}
}
namespace FootballSim.ViewModels
{
using Catel.MVVM;
using FootballSim.Models;
using System.Collections.Generic;
/// <summary>
/// UserControl view model.
/// </summary>
public class PlayersViewModel : ViewModelBase, IPlayersViewModel
{
public List<Player> Players { get; protected set; }
public PlayersViewModel(List<Player> players) : base()
{
Players = players;
}
public override string Title { get { return "View model title"; } }
// TODO: Register models with the vmpropmodel codesnippet
// TODO: Register view model properties with the vmprop or vmpropviewmodeltomodel codesnippets
// TODO: Register commands with the vmcommand or vmcommandwithcanexecute codesnippets
}
}
There are several ways of navigating in Catel:
IUIVisualizerService => show other dialogs
INavigationService => navigate to pages / close application / etc
Maybe it's a good idea for you to read the getting started guide of Catel.

My WPF program will not run

I am making a simple picture viewer application where it gets all the images from a folder and I can look at them all switching between them by clicking Previous and Next buttons.
Whenever I run my program I get this error the call stack contains only external code. I have googled it and tbh I really don't get what this error means at all, and right now I just want to fix it so my program can start. So can you guys look at my code and help me fix the problem?
Heres the XAML for the window
<Window x:Class="PictureViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="700">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<Button Name="button_Previous" Margin="0,0,10,5" HorizontalAlignment="Left" Width="75" Height="Auto" DockPanel.Dock="Left" Content="Previous" Click="button_Previous_Click" />
<Button Name="button_Next" Margin="0,0,10,5" HorizontalAlignment="Left" Width="75" Height="Auto" DockPanel.Dock="Left" Content="Next" Click="button_Next_Click" />
<Button Name="button_Browse" Margin="0,0,10,5" HorizontalAlignment="Left" Width="75" Height="Auto" DockPanel.Dock="Left" Content="Browse" />
</DockPanel>
<Rectangle Grid.Row="1" Fill="LightBlue" />
<Image Grid.Row="1" Margin="15" Name="image_Picture" Stretch="Fill" />
</Grid>
</Window>
The code behind the window:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace PictureViewer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
cPicture Picture;
public MainWindow()
{
InitializeComponent();
Picture = new cPicture();
Picture.Initialize();
DisplayPicture();
}
private void button_Previous_Click(object sender, RoutedEventArgs e)
{
Picture.Previous();
DisplayPicture();
}
private void button_Next_Click(object sender, RoutedEventArgs e)
{
Picture.Next();
DisplayPicture();
}
private void DisplayPicture()
{
BitmapImage image = new BitmapImage(new Uri(Picture.PictureList[Picture.CurrentPictureNumber]));
image_Picture.Source = image;
}
}
}
Also my Picture class:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PictureViewer
{
class cPicture
{
List<string> pictureList;
int currentPictureNumber = 0;
public List<string> PictureList
{
get { return pictureList; }
set { pictureList = value; }
}
public int CurrentPictureNumber
{
get { return currentPictureNumber; }
}
public void Initialize()
{
Directory.GetFiles(#"C:\Users\Syeda\Desktop\Photos");
List<string> pictureList = new List<string>(Directory.GetFiles(#"C:\Users\Syeda\Desktop\Photos"));
}
public void Next()
{
currentPictureNumber = currentPictureNumber + 1;
if (currentPictureNumber > pictureList.Count)
{
currentPictureNumber = 0;
}
}
public void Previous()
{
currentPictureNumber = currentPictureNumber - 1;
if (currentPictureNumber < 0)
{
currentPictureNumber = pictureList.Count;
}
}
}
}
here is a working implementation of what you were trying to accomplish. I utilized the MVVM Pattern. Typically when building small WPF applications this simplifies a lot of the work that needs to be done behind the scene. Enjoy :)
PicureViewer Class:
namespace Stack
{
public class PictureViewer : INotifyPropertyChanged
{
private const string PictureDirectory = #"C:\Users\TMoore\Pictures";
public int CurrentPictureNumber { get; set; }
private string currentImagePath;
public string CurrentImagePath
{
get { return currentImagePath; }
set
{
currentImagePath = value;
OnPropertyChanged();
}
}
private IList<string> pictureList { get; set; }
public IList<string> PictureList
{
get { return pictureList ?? (pictureList = new List<string>()); }
set { pictureList = value; }
}
public PictureViewer()
{
// you should add a search pattern
pictureList = Directory.EnumerateFiles(PictureDirectory)
.ToList();
CurrentImagePath = pictureList[0];
}
public void Next()
{
CurrentImagePath = CurrentPictureNumber > pictureList.Count() - 1
? PictureList[0]: PictureList[CurrentPictureNumber++];
}
public void Previous()
{
CurrentImagePath = CurrentPictureNumber == 0
? PictureList[PictureList.Count()-1] : PictureList[CurrentPictureNumber--];
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
XAML:
<Window x:Class="Stack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<Button Name="button_Previous" Margin="0,0,10,5" HorizontalAlignment="Left" Width="75" Height="Auto" DockPanel.Dock="Left" Content="Previous" Click="button_Previous_Click" />
<Button Name="button_Next" Margin="0,0,10,5" HorizontalAlignment="Left" Width="75" Height="Auto" DockPanel.Dock="Left" Content="Next" Click="button_Next_Click" />
<Button Name="button_Browse" Margin="0,0,10,5" HorizontalAlignment="Left" Width="75" Height="Auto" DockPanel.Dock="Left" Content="Browse" />
</DockPanel>
<Rectangle Grid.Row="1" Fill="LightBlue" />
<Image Grid.Row="1" Margin="15" Source="{Binding CurrentImagePath, UpdateSourceTrigger=PropertyChanged}" Stretch="Fill" />
</Grid>
</Window>
Code Behind:
public partial class MainWindow : Window
{
PictureViewer viewer { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = viewer ?? (viewer = new PictureViewer());
}
private void button_Previous_Click(object sender, RoutedEventArgs e)
{
viewer.Previous();
}
private void button_Next_Click(object sender, RoutedEventArgs e)
{
viewer.Next();
}
}
pictureList is a local variable in your Initialise method - so the Global PictureList will always be empty
change Initialise to
public void Initialize()
{
pictureList = new List<string>(Directory.GetFiles(#"C:\Users\Syeda\Desktop\Photos"));
}
(also no point doing the redundant GetFiles line first)
For starters:
public void Initialize()
{
Directory.GetFiles(#"C:\Users\Syeda\Desktop\Photos");
List<string> pictureList = new List<string>(Directory.GetFiles(#"C:\Users\Syeda\Desktop\Photos"));
}
You are creating a local variable pictureList which overrides your member declaration. This method should be:
public void Initialize()
{
pictureList = new List<string>(Directory.GetFiles(#"C:\Users\Syeda\Desktop\Photos"));
}
Also, look at the picturelist in debug and see the files that get added on. For starters I suggest adding "*.jpg". This will ensure that only the jpg files paths are added to pictureList. So now the above method will look like this:
public void Initialize()
{
pictureList = new List<string>(Directory.GetFiles(#"C:\Users\Syeda\Desktop\Photos"), "*.jpg");
}
Also, the check code should compare with ">=" like this:
public void Next()
{
currentPictureNumber = currentPictureNumber + 1;
if (currentPictureNumber >= pictureList.Count)
{
currentPictureNumber = 0;
}
}
Same goes for the Previous method:
public void Previous()
{
currentPictureNumber = currentPictureNumber - 1;
if (currentPictureNumber < 0)
{
currentPictureNumber = pictureList.Count - 1;
}
}

Is there some way I can use assign a value in MainPage and bind it in the child window

I've a Silverlight application wherein I've a MainPage in which I need to assign a variable Name in the childwindow and assign it without using the object of the child. I need to bind thise value to a textbox in the Childwindow through XAML. How can it be done?
So far what I've done is using a dependancy property in the childwindow:
nameProp = DependencyProperty.Register("strName", typeof(string), typeof(TestWindow), new PropertyMetadata(null, new PropertyChangedCallback(OnNameChange)));
static TestWindow()
{
nameProp = DependencyProperty.Register("strName", typeof(string), typeof(TestWindow), new PropertyMetadata(null, new PropertyChangedCallback(OnNameChange)));
}
private static void OnNameChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.SetValue(nameProp, e.NewValue);
}
public string strName
{
get {
return (string)GetValue(nameProp);
}
set {
SetValue(nameProp, value);
}
}
and in TestWindow XAML i try to bind it:
<TextBox Text="{Binding Path=strName}" Height="23" HorizontalAlignment="Left" Margin="126,84,0,0" Name="txtName" VerticalAlignment="Top" Width="120"/>
How can I set the value for this dp from MainPage. Or is there any better alternative?
One way will be:
Make those variables public properties of your MainPage.
Assign the mainPage to be your child window DataContext.
Bind to those properties via XAML in your childWindow.
i am hoping that this will helps you....what you are trying to achieve....
ChildWindow Xaml file:
<controls:ChildWindow x:Class="ParentToChildWindow.ChildWindowControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
Width="400" Height="300"
Title="Pass Data from Parent to ChildWindow">
<Grid x:Name="LayoutRoot" Margin="2">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical">
<TextBlock x:Name="txtValue" />
<TextBlock x:Name="txtName"/>
</StackPanel>
<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75"
Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
<Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23"
HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
</Grid>
</controls:ChildWindow>
ChildWindow CS file:
namespace ParentToChildWindow
{
using System.Windows;
using System.Windows.Controls;
public partial class ChildWindowControl : ChildWindow
{
public int Value { get; set; }
public string Name { get; set; }
public ChildWindowControl()
{
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.txtValue.Text = this.Value.ToString();
this.txtName.Text = this.Name;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
}
}
Parent CS File: I have added a button to parent XAML and added a click event
private void HandleButtonClickEvent(object sender, RoutedEventArgs e)
{
ChildWindowControl childControl = new ChildWindowControl();
childControl.Value = 10;
childControl.Name = "Data From Parent XAML to ChildWindow";
childControl.Show();
}
Pass the value in the constructor of theChildWindow
For this the place where we create the new instance of ChildWindow, we need to pass the required values to the Constructor. But remember, there must be a matching constructor already present in the ChildWindow control.
public ChildWindowControl(int value, string name)
{
InitializeComponent();
this.Value = value;
this.Name = name;
}
That is all that is required to pass the data from Parent XAML to ChildWindow

Categories