I want to display the kinect status-Connected or disconnected and the Device Connection ID.
Connection ID is getting displayed,but Status is not getting displayed in Textblock
My code is-
mainwindow.xaml.cs-
public partial class MainWindow : Window
{
KinectSensor sensor;
private MainWindowViewModel viewModel;
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
this.viewModel = new MainWindowViewModel();
this.DataContext = this.viewModel;
}
void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
{
switch (e.Status)
{
case KinectStatus.Connected:
txtBlckStatus.Text = "Connected";
break;
case KinectStatus.Disconnected:
txtBlckStatus.Text = "Disconnected";
break;
}
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
if (KinectSensor.KinectSensors.Count > 0)
{
this.sensor = KinectSensor.KinectSensors[0];
KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;
this.StartSensor();
this.sensor.ColorStream.Enable();
this.sensor.DepthStream.Enable();
this.sensor.SkeletonStream.Enable();
}
else
{
MessageBox.Show("No Sensor Connected!!");
this.Close();
}
}
private void StartSensor()
{
if(this.sensor!=null && !this.sensor.IsRunning)
{
this.sensor.Start();
SetKinectInfo();
}
}
private void StopSensor()
{
if (this.sensor != null && !this.sensor.IsRunning)
{
this.sensor.Stop();
}
}
private void SetKinectInfo()
{
if(this.sensor!=null)
{
this.viewModel.ConnectionID = this.sensor.DeviceConnectionId;
}
}
}
mainwindow.xaml
<Window x:Class="KinectInfoBox.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>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Status:"></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="1" x:Name="txtBlckStatus"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Connection ID"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding ConnectionID}"></TextBlock>
<Button Grid.Row="2" Grid.ColumnSpan="2" Content="Stop" Margin="179,81,179,42" x:Name="StopSensorButton"></Button>
</Grid>
</Grid>
</Window>
mainwindowviewmodel.cs--to display the changing connection id
namespace KinectInfoBox
{
public class MainWindowViewModel:INotifyPropertyChanged
{
private string _connectionIDValue;
public string ConnectionID
{
get { return _connectionIDValue; }
set
{
if(this._connectionIDValue!=value)
{
this._connectionIDValue = value;
this.OnNotifyPropertyChange("ConnectionID");
}
}
}
public void OnNotifyPropertyChange(string propertyName)
{
if(this.PropertyChanged!=null)
{
this.PropertyChanged.Invoke(this,newPropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
The code is perfectly allright,actually the kinect is initially connected with the system,so there is no state changed,but when you unplug the kinect then the status change even is triggered,so you will see the status disconnected in the textblock and when you connect ity again the status connected will get displayed there.
Related
Problem
I want to refresh my wpf view when a change is made in a List of objects in my application, but it wont register the INotifyChanged method when I change a value.
What I've tried
I went to multiple different stackoverflow pages with sort of the same problem but I don't get it working right. It wont register a change in a object in the list.
my code
below is the code for the MainWindow of the WPF application in wher with the last button click I change the value of XLocation in an object out of a list.
public partial class MainWindow : Window
{
private string filePathArtist { get; set; }
private string filePathGrid { get; set; }
public Game.Game Game { get; set; }
public MainWindow()
{
InitializeComponent();
filePathGrid = String.Empty;
filePathArtist = String.Empty;
}
private void BtnOpen_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
bool? res = openFileDialog.ShowDialog();
if (res == true)
{
string filepathgrid = openFileDialog.FileName;
filePathGrid = filepathgrid;
GridTextBox.Text = filepathgrid;
}
}
private void PickArtistBtn_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
bool? res = openFileDialog.ShowDialog();
if (res == true)
{
string filepathartist = openFileDialog.FileName;
filePathArtist = filepathartist;
ArtistTextBox.Text = filepathartist;
}
}
private void CreateGridBtn_Click(object sender, RoutedEventArgs e)
{
Game = new Game.Game(filePathGrid, filePathArtist);
this.DataContext = Game;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Game.Artists[0].XLocation = 30;
}
}
Next code is the Game class where is implemented a INotfyPropertyChanged on the list of Artists.
public class Game : INotifyPropertyChanged
{
public List<Artist> _artists;
public List<Artist> Artists
{
get
{
return _artists;
}
set
{
_artists = value;
OnPropertyChanged("Artists");
}
}
public List<ITile> Tiles { get; set; }
public Game()
{
}
public Game(string graphPath, string artistPath)
{
IDataParser graphParser = DataFactory.DataFactory.Instance.CreateParser(graphPath);
IDataParser artistParser = DataFactory.DataFactory.Instance.CreateParser(artistPath);
Tiles = graphParser.ParseGridData(graphPath);
Artists = artistParser.ParseArtistData(artistPath);
Test = "new Game";
}
public string Test { get; set; } = "t";
public event PropertyChangedEventHandler? PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Ive also added the INotifyPropertyChanged in the Artists class
public class Artist : INotifyPropertyChanged
{
private float _xLocation;
private float _yLocation;
private int _xVelocity;
private int _yVelocity;
public float XLocation
{
get => _xLocation;
set
{
_xLocation = value;
OnPropertyChanged("XLocation");
}
}
public float ConvertedXLoc
{
get => XLocation * (float)3.75;
set { }
}
public float YLocation
{
get => _yLocation;
set
{
_yLocation = value;
OnPropertyChanged("YLocation");
}
}
public float ConvertedYLoc
{
get => YLocation * (float)3.75;
set { }
}
public int XVelocity
{
get => _xVelocity;
set
{
_xVelocity = value;
}
}
public int YVelocity
{
get => _yVelocity;
set
{
_yVelocity = value;
}
}
public event PropertyChangedEventHandler? PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then here is the Xaml code where I bind the objects to the wpf UI.
<Window x:Class="BroadwayBoogie.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:game="clr-namespace:BroadwayBoogie.Game"
mc:Ignorable="d"
Title="MainWindow" Height="900" Width="900"
>
<Window.DataContext>
<game:Game/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="201*"/>
<ColumnDefinition Width="199*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="21*"/>
<RowDefinition Height="401*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Button x:Name="BtnOpen" Content="Pick Grid" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Click="BtnOpen_Click"/>
<TextBox x:Name="GridTextBox" HorizontalAlignment="Center" TextWrapping="NoWrap" VerticalAlignment="Center" Width="266" />
<Button x:Name="PickArtistBtn" Content="Pick Artist" HorizontalAlignment="Left" Margin="356,0,0,0" VerticalAlignment="Center" Click="PickArtistBtn_Click" RenderTransformOrigin="-0.135,0.647"/>
<TextBox x:Name="ArtistTextBox" HorizontalAlignment="Left" Margin="30,14,0,0" TextWrapping="NoWrap" VerticalAlignment="Top" Width="231" Grid.Column="1"/>
<Button x:Name="CreateGridBtn" Grid.Column="1" Content="Create Grid" HorizontalAlignment="Left" Margin="311,14,0,0" VerticalAlignment="Top" Click="CreateGridBtn_Click"/>
<Canvas Width="800" Height="800" Grid.ColumnSpan="2" Margin="49,15,51,27" Grid.Row="1" Background="DarkSeaGreen" Grid.RowSpan="2">
<ItemsControl Name="tilesItemsControl" ItemsSource="{Binding Tiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Rectangle
Width="15"
Height="15"
Fill="{Binding Color}"
Canvas.Left ="{Binding ConvertedXLoc}"
Canvas.Top="{Binding ConvertedYLoc}" />
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Name="ArtistItemsControl" ItemsSource="{Binding Artists}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Rectangle
Width="3.75"
Height="3.75"
Fill="Black"
Canvas.Left ="{Binding ConvertedXLoc}"
Canvas.Top="{Binding ConvertedYLoc}" />
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
<Grid/>
<Button Content="Button" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Row="2" VerticalAlignment="Center" Click="Button_Click"/>
</Grid>
So with the press of the button I added for testing purposes. It changes a value in the List and then the PropertyChanged method should detect that but it doesn't detect it it just skips it.
Question
So my basic question is, how do I detect the change of a property from objects out of the List of Artists.
OnPropertyChanged will only be executed when the property itself is changed. A new item in a list is not a property change. That's the reason why no updates happens.
Instead a List, try an ObservableCollection. An ObservableCollection implements an additional INotifyCollectionChanged which makes the UI able to react on changing items in the list.
I'm writing my first universal windows app and am currently experimenting with the accelerometer.
Currently I'm displaying it's reading as numbers on the screen but I would like to also show a graph that depicts these values visually.
I've seen some charting examples online but none that accept a live stream of data and display it as it comes in.
Basically what I want is a graph over the time domain that draws a line which represents the values the accelerometer outputs.
This is my first attempt at windows programming and I'm working with C#.
Is there a 'proper' way to do such a thing? a commonly accepted method?
Use WinRTXamlToolkit:
XAML:
<Page
x:Class="App3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Charting="using:WinRTXamlToolkit.Controls.DataVisualization.Charting"
mc:Ignorable="d" Loaded="Page_Loaded">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="10*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Charting:Chart x:Name="chart1" Grid.Row="0">
<Charting:LineSeries ItemsSource="{Binding Data}"
DependentValuePath ="Accel"
IndependentValuePath ="Timestamp" Margin="0"/>
</Charting:Chart>
<Button x:Name="btnStart" Content="START" Grid.Row="1" Click="btnStart_Click" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Button>
<Button x:Name="btnStop" Content="STOP" Grid.Row="2" Click="btnStop_Click" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Button>
</Grid>
</Page>
MainPage:
public sealed partial class MainPage : Page
{
MyViewModel vm;
public MainPage()
{
this.InitializeComponent();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
vm = new MyViewModel();
DataContext = vm;
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
vm.Start();
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
vm.Stop();
}
}
ViewModel:
public class MyViewModel
{
private Timer accelerometer;
private Random r;
private ObservableCollection<MyAccelModel> data;
public ObservableCollection<MyAccelModel> Data { get { return data; } }
public MyViewModel()
{
data = new ObservableCollection<MyAccelModel>();
r = new Random(DateTime.Now.Millisecond);
}
public void Start()
{
accelerometer = new Timer(AccelDataCallback, null, 100, 500);
}
public void Stop()
{
accelerometer.Dispose();
}
private async void AccelDataCallback(object state)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
data.Add(new MyAccelModel { Timestamp = DateTime.Now, Accel = r.NextDouble() });
});
}
}
Please allow me to present a simplified version of my problem:
Lets say I have a main window called MainWindow in which I would like to display some Person objects in MainWindow. Now, in order to instantiate these Person objects I need a bunch of different fields such as name, age, profession, favourite food, etc...
Here is my solution:
I try to get all input fields and instantiate a Person in a secondary window and then send back the result to the main form.
MainWindow has a public method as follows:
public void (Person input)
{
// use the fields in input to add details to window
}
I have another window in the project called PersonInput that takes in its constructor a reference to a MainWindow and saves it in a field.
private MainWindow owner;
public PersonInput(MainWindow parent)
{
InitializeComponent();
owner = parent;
}
PersonInput has a number of input fields corresponding to the required fields of a Person object.
in addition it has a button called "AddPerson" with an associated onClick event handler as follows: (pseudoCode)
private void button_Click(object sender, RoutedEventArgs e)
{
//get all fields from this form..
String enteredName = this.nameText.Text;
//get more fields....
Person p = new Person(...);
//owner is MainWindow, send Back the Person so details can be displayed
owner.addPerson(p);
this.Close();
}
as you would expect, MainWindow has a Button named "AddPersonButton" which has an on click event handler like this:
private void button_Click(object sender, RoutedEventArgs e)
{
PersonInput x = new PersonInput(this); //pass this as a reference
//so this window can send us back the result when they have it
x.Show(); //open the child window so user can enter information
}
While this method works, I am quite convinced it is not the best practice way to do it. I would like to learn the idiomatic .net WPF way of doing this. Please enlighten me
PersonInput.xaml.cs
public class PersonInput : Window
{
public void PersonInput()
{
InitializeComponent();
Owner = Application.Current.MainWindow;
}
public static Person ShowDialog(Person initializer)
{
var vm = new PersonViewModel(initializer);
var dlg = new PersonInput() { DataContext = vm };
if (dlg.ShowDialog().GetValueOrDefault(false))
{
return vm.ToPerson();
}
return null;
}
private void OK_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
}
}
PersonInputViewModel.cs
public class PersonViewModel : ViewModelBase
{
public PersonViewModel(Person person = null)
{
if (person != null)
{
// Assuming Person has FirstName and LastName properties
FirstName = person.FirstName;
LastName = person.LastName;
// etc. etc. for all the rest
}
}
public Person ToPerson()
{
return new Person()
{
FirstName = this.FirstName,
LastName = this.LastName,
// etc. etc. for all other properties
};
}
private string _firstName = null;
public string FirstName {
get { return _firstName; }
set {
if (value != _firstName) {
_firstName = value;
OnPropertyChanged(nameof(FirstName));
}
}
}
}
ViewModelBase.cs
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
PersonInput.xaml
<Window xmlns:blahblahblah="Blah blah blah" etc etc
Title="Person"
Height="640"
Width="480"
ShowInTaskbar="False"
ResizeMode="CanResizeWithGrip"
WindowStartupLocation="CenterOwner"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="180" Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">First Name</Label>
<TextBox
Grid.Row="0"
Grid.Column="1"
Text="{Binding FirstName}"
/>
<Label Grid.Row="1" Grid.Column="0">Last Name</Label>
<TextBox
Grid.Row="1"
Grid.Column="1"
Text="{Binding LastName}"
/>
<StackPanel
Orientation="Horizontal"
Grid.Column="1"
Grid.Row="10"
HorizontalAlignment="Right"
>
<Button Content="_OK" Click="OK_Click" />
<Button Content="_Cancel" Click="Cancel_Click" />
</StackPanel>
</Grid>
</Window>
The biggest weakness of this approach is the strong coupling between MainWindow and PersonInput.
A slightly better approach would be to use Observer Pattern and have the Main Window anonymously subscribe.
Simple solution example code:
public interface IAddPersonObserver
{
void OnPersonAdded(Person person);
}
public interface IAddPersonObservable
{
void Subscribe(IAddPersonObserver observer);
void Unsubscribe(IAddPersonObserver observer);
}
public class MainWindow : IAddPersonObserver
{
...
private void button_Click(object sender, RoutedEventArgs e)
{
PersonInput x = new PersonInput();
x.Subscribe(this);
x.Show();
}
public void OnPersonAdded(Person addedPerson)
{
addPerson(addedPerson); // or whatever view update code you want
}
}
Further improvements would revolve around separating the MainWindow from knowing what view gets created or shown, and having an intermediary object (such as a PersonRepository) store/hold/provide the important business data. This is much better than having the application data actually live inside the Views and Application Windows.
Another use MVVM practice:
Solution structure
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
}
public class PersonListViewModel : DependencyObject {
public ObservableCollection<Person> Items { get; set; }
public Person CurrentPerson
{
get { return (Person)GetValue(CurrentPersonProperty); }
set { SetValue(CurrentPersonProperty, value); }
}
public static readonly DependencyProperty CurrentPersonProperty = DependencyProperty.Register("CurrentPerson", typeof(Person), typeof(PersonListViewModel));
public ICommand AddCommand { get; set; }
public ICommand EditCommand { get; set; }
public PersonListViewModel() {
Items = new ObservableCollection<Person>();
AddCommand = new RelayCommand(p=> add() );
EditCommand = new RelayCommand(p=> { return CurrentPerson != null; }, p => edit());
}
private void add() {
Person p= new Person();
p.Id = Items.Count();
p.Name = "New Name";
p.Birthday = DateTime.Now;
Items.Add(p);
}
private void edit() {
var viewModel = new PersonItemViewModel(CurrentPerson);
var view = new View.PersonEditWindow();
view.DataContext = viewModel;
view.Show();
}
}
public class PersonItemViewModel : DependencyObject {
Person person;
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(PersonItemViewModel) );
public DateTime Birthday
{
get { return (DateTime)GetValue(BirthdayProperty); }
set { SetValue(BirthdayProperty, value); }
}
public static readonly DependencyProperty BirthdayProperty = DependencyProperty.Register("Birthday", typeof(DateTime), typeof(PersonItemViewModel));
public PersonItemViewModel() {
}
public PersonItemViewModel(Person source) {
this.person = source;
Name = person.Name;
Birthday = person.Birthday;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) {
base.OnPropertyChanged(e);
if (e.Property == NameProperty) {
person.Name = (string) e.NewValue;
}
if (e.Property == BirthdayProperty) {
person.Birthday = (DateTime)e.NewValue;
}
}
}
List Form:
<Window x:Class="WpfApplication1.View.PersonListWindow"
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:local="clr-namespace:WpfApplication1.View"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Title="PersonListWindow" Height="300" Width="300"
xmlns:viewModel="clr-namespace:WpfApplication1.ViewModel"
d:DataContext="{d:DesignInstance Type=viewModel:PersonListViewModel, IsDesignTimeCreatable=True}"
>
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Items}" SelectedItem="{Binding CurrentPerson, Mode=TwoWay}">
</DataGrid>
<StackPanel Grid.Row="1" Height="32" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Margin="4" Command="{Binding AddCommand}">Add</Button>
<Button Margin="4" Command="{Binding EditCommand}">Edit</Button>
</StackPanel>
</Grid>
Edit Form:
<Window x:Class="WpfApplication1.View.PersonEditWindow"
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:WpfApplication1.View"
mc:Ignorable="d"
Title="PersonEditWindow" Height="300" Width="300"
xmlns:viewModel="clr-namespace:WpfApplication1.ViewModel"
d:DataContext="{d:DesignInstance Type=viewModel:PersonItemViewModel, IsDesignTimeCreatable=True}"
>
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0">Name</TextBlock>
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding Name}"></TextBox>
<TextBlock Grid.Row="1">Birthday</TextBlock>
<TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Birthday}"></TextBox>
</Grid>
Results (Image)
I have structured the classes like this for my Universal app. Currently working in the WP8.1 part.
The following classes are put in the shared code. (Hoping to use it in Win8.1)
FolderItemViewer.xaml(UserControl) It is the DataTemplate for a ListView in the MainPage.xaml
FolderCollection class, which is the collection that is bound to the Listview in the Mainpage.xaml of the WP
Now the problem is, I have wired the manipulation events to the datatemplate grids in the FolderItemViewer.xaml to capture the right and left swipe and it is working. Now based on this, I need to update that CollectionItem in FolderCollection class and hence the ListView in Mainpage.xaml.
How do I capture that listview item or the collectionitem bound since the manipulation events lie in the FolderItemViewer class?
Can I get the listview item? Or a call back function to the listlivew item template changed? or somethin like that?
EDIT
Sorry to put in so much code. But really appreciate somebody's help in getting this right.
This is the FolderItemViewer.xaml
<UserControl
x:Class="JusWrite2.FolderItemViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:JusWrite2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="MainGrid">
<Grid Height="60" Width="380" Margin="0,0,0,1">
<Grid x:Name="ItemGrid" HorizontalAlignment="Left" VerticalAlignment="Center" Width="380" Height="60" Background="Transparent" Canvas.ZIndex="2"
ManipulationMode="TranslateX,System" ManipulationStarted="On_ChannelItem_ManipulationStarted" ManipulationDelta="On_ChannelItem_ManipulationDelta" ManipulationCompleted="OnChannelItemManipulationCompleted">
<TextBlock x:Name="titleTextBlock" Margin="20,0,0,0" Canvas.ZIndex="2" VerticalAlignment="Center" TextAlignment="Left" FontSize="25" >
</TextBlock>
</Grid>
<Grid x:Name="DelGrid" Opacity="0.0" HorizontalAlignment="Right" VerticalAlignment="Center" Height="60" Background="Red" Canvas.ZIndex="-1" Tapped="On_ChannelDelete_Tap" Width="380">
<Button Content="X" FontSize="25" Canvas.ZIndex="-1" VerticalAlignment="Center" HorizontalAlignment="Center" Width="380" BorderThickness="0" />
</Grid>
</Grid>
</Grid>
</UserControl>
code behind
private void OnChannelItemManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
Grid ChannelGrid = (Grid)sender;
Grid mGrid = (Grid)(ChannelGrid.Parent);
Grid DeleteGrid = (Grid)((Grid)(ChannelGrid.Parent)).Children[1];
FolderCollection swipedItem = ChannelGrid.DataContext as FolderCollection;// grid has null value for datacontext
double dist = e.Cumulative.Translation.X;
if (dist < -100)
{
// Swipe left
}
else
{
// Swipe right
}
}
FolderCollection.xaml has two classes in it. FolderItem and FolderCollection
public class FolderItem : INotifyPropertyChanged
{
// variables
public FolderItem()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public int CompletionStatus
{
//code
}
public int Priority
{
//code
}
public string FolderText
{
//code
}
public int PenColor
{
//code
}
public string UUID
{
//code
}
public string CreateUUID()
{
//code
}
}
public class FolderCollection : IEnumerable<Object>
{
private ObservableCollection<FolderItem> folderCollection = new ObservableCollection<FolderItem>();
private static readonly FolderCollection instance = new FolderCollection();
public static FolderCollection Instance
{
get
{
return instance;
}
}
public IEnumerator<Object> GetEnumerator()
{
return folderCollection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(FolderItem fItem)
{
folderCollection.Add(fItem);
}
public ObservableCollection<FolderItem> FolderCollectionInstance
{
get
{
return folderCollection;
}
}
}
And this is the MainPage.xaml where I have data bound.
// Resources
<DataTemplate x:Key="StoreFrontTileTemplate">
<local:FolderItemViewer />
</DataTemplate>
<ListView x:Name="FolderListView" ItemsSource="{Binding}"
SelectionMode="None"
ItemTemplate="{StaticResource StoreFrontTileTemplate}"
ContainerContentChanging="ItemListView_ContainerContentChanging">
</ListView>
code behind
//Constructor
FolderListView.DataContext = fc.FolderCollectionInstance;
FolderListView.ItemsSource = fc.FolderCollectionInstance;
private void ItemListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
FolderItemViewer iv = args.ItemContainer.ContentTemplateRoot as FolderItemViewer;
if (args.InRecycleQueue == true)
{
iv.ClearData();
}
else if (args.Phase == 0)
{
iv.ShowPlaceholder(args.Item as FolderItem);
// Register for async callback to visualize Title asynchronously
args.RegisterUpdateCallback(ContainerContentChangingDelegate);
}
else if (args.Phase == 1)
{
iv.ShowTitle();
args.RegisterUpdateCallback(ContainerContentChangingDelegate);
}
else if (args.Phase == 2)
{
//iv.ShowCategory();
//iv.ShowImage();
}
// For imporved performance, set Handled to true since app is visualizing the data item
args.Handled = true;
}
private TypedEventHandler<ListViewBase, ContainerContentChangingEventArgs> ContainerContentChangingDelegate
{
get
{
if (_delegate == null)
{
_delegate = new TypedEventHandler<ListViewBase, ContainerContentChangingEventArgs>(ItemListView_ContainerContentChanging);
}
return _delegate;
}
}
private TypedEventHandler<ListViewBase, ContainerContentChangingEventArgs> _delegate;
The list item should be available as the data context of the grid: ChannelGrid.DataContext.
I have the following method that is executed in a button click:
private void CopyDirectoriesAndFiles(string source, string target, string[] excludedFolders)
{
foreach (string dir in Directory.GetDirectories(source, "*", System.IO.SearchOption.AllDirectories))
if (!excludedFolders.Contains(dir))
Directory.CreateDirectory(target + dir.Substring(source.Length));
foreach (string file_name in Directory.GetFiles(source, "*.*", System.IO.SearchOption.AllDirectories))
if (!File.Exists(Path.Combine(target + file_name.Substring(source.Length))))
File.Copy(file_name, target + file_name.Substring(source.Length));
}
The button click has some other methods, but they don't take very long to run, but even so, how can I show and update a progress bar for each even that is run. I put a textbox, but it only writes to the textbox once it is finished with everything. My button order may looks like this:
InitializeStuff();
CopyFiles();
CleanUp();
A progress bar is not absolutely necessary, although nice. It would be great if I could get my textbox to update at each time a method completed instead of at the very end.
Here's a complete working model using MVVM:
The View:
<Window x:Class="CopyFiles.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"
xmlns:model="clr-namespace:CopyFiles">
<Window.DataContext>
<model:CopyModel />
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Name="sourceLabel">Source</Label>
<TextBox Text="{Binding Source, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="0" Grid.Column="1" Name="sourceTextBox" Margin="5"/>
<Label Grid.Row="1" Grid.Column="0" Name="destinationLabel">Destination</Label>
<TextBox Text="{Binding Destination, Mode =TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.Column="1" Name="destinationTextBox" Margin="5" />
<Button Command="{Binding CopyCommand}" Grid.Row="2" Grid.ColumnSpan="2" Content="Copy" Name="copyButton" Width="40" HorizontalAlignment="Center" Margin="5"/>
<ProgressBar Visibility="{Binding CopyInProgress, Converter={StaticResource booleanToVisibilityConverter}}" Value="{Binding Progress}" Grid.Row="3" Grid.ColumnSpan="2" Height="20" Name="copyProgressBar" Margin="5" />
</Grid>
</Window>
The ViewModel:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using Microsoft.Practices.Prism.Commands;
namespace CopyFiles
{
public class CopyModel: INotifyPropertyChanged
{
private string source;
private string destination;
private bool copyInProgress;
private int progress;
private ObservableCollection<string> excludedDirectories;
public CopyModel()
{
this.CopyCommand = new DelegateCommand(ExecuteCopy, CanCopy);
this.excludedDirectories = new ObservableCollection<string>();
}
public event PropertyChangedEventHandler PropertyChanged;
public string Source
{
get { return source; }
set
{
source = value;
RaisePropertyChanged("Source");
CopyCommand.RaiseCanExecuteChanged();
}
}
public string Destination
{
get { return destination; }
set
{
destination = value;
RaisePropertyChanged("Destination");
CopyCommand.RaiseCanExecuteChanged();
}
}
public bool CopyInProgress
{
get { return copyInProgress; }
set
{
copyInProgress = value;
RaisePropertyChanged("CopyInProgress");
CopyCommand.RaiseCanExecuteChanged();
}
}
public int Progress
{
get { return progress; }
set
{
progress = value;
RaisePropertyChanged("Progress");
}
}
public ObservableCollection<string> ExcludedDirectories
{
get { return excludedDirectories; }
set
{
excludedDirectories = value;
RaisePropertyChanged("ExcludedDirectories");
}
}
public DelegateCommand CopyCommand { get; set; }
public bool CanCopy()
{
return (!string.IsNullOrEmpty(Source) &&
!string.IsNullOrEmpty(Destination) &&
!CopyInProgress);
}
public void ExecuteCopy()
{
BackgroundWorker copyWorker = new BackgroundWorker();
copyWorker.DoWork +=new DoWorkEventHandler(copyWorker_DoWork);
copyWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(copyWorker_RunWorkerCompleted);
copyWorker.ProgressChanged += new ProgressChangedEventHandler(copyWorker_ProgressChanged);
copyWorker.WorkerReportsProgress = true;
copyWorker.RunWorkerAsync();
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if(handler != null)
{
var eventArgs = new PropertyChangedEventArgs(propertyName);
handler(this, eventArgs);
}
}
private void copyWorker_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
this.CopyInProgress = true;
worker.ReportProgress(0);
var directories = Directory.GetDirectories(source, "*", System.IO.SearchOption.AllDirectories);
var files = Directory.GetFiles(source, "*.*", System.IO.SearchOption.AllDirectories);
var total = directories.Length + files.Length;
int complete = 0;
foreach (string dir in directories)
{
if (!ExcludedDirectories.Contains(dir))
Directory.CreateDirectory(destination + dir.Substring(source.Length));
complete++;
worker.ReportProgress(CalculateProgress(total, complete));
}
foreach (string file_name in files)
{
if (!File.Exists(Path.Combine(destination + file_name.Substring(source.Length))))
File.Copy(file_name, destination + file_name.Substring(source.Length));
complete++;
worker.ReportProgress(CalculateProgress(total, complete));
}
}
private static int CalculateProgress(int total, int complete)
{
// avoid divide by zero error
if (total == 0) return 0;
// calculate percentage complete
var result = (double)complete / (double)total;
var percentage = result * 100.0;
// make sure result is within bounds and return as integer;
return Math.Max(0,Math.Min(100,(int)percentage));
}
private void copyWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.Progress = e.ProgressPercentage;
}
private void copyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.CopyInProgress = false;
}
}
}
I have the following method that is executed in a button click:
It shouldn't be. This will freeze your UI for too long.
Use a Backgroundworker. [1], [2] and [3]