How to Programmatically create Grid within row of a Grid in Wpf - c#

I am working in WPF -- There is button with click event handler in my application. As i click on button it's event handler generates a new row in grid named as grids. In this new Row i want to add another grid programmatically to add Label, Button and TextBox in this grid in row.
As i executed my code it only generates a texboxes! where labels and button shown once! Here code and image is : Please feel free to ask if my query is not clear to you!
int r =0;
private void button2_Click(object sender, RoutedEventArgs e)
{
TextEdit text1; Button button1; Grid grid1;
grids.RowDefinitions.Add(new RowDefinition());
text1 = new TextEdit();
text1.SetValue(Grid.ColumnProperty, 1);
text1.SetValue(Grid.RowProperty, r);
button1 = new Button();
button1.Content = "Left + " + r;
button1.Click += new RoutedEventHandler(button1_Click);
button1.SetValue(Grid.ColumnProperty, 1);
button1.SetValue(Grid.RowProperty, r);
grid1 = new Grid();
grid1.SetValue(Grid.ColumnProperty, 1);
grids.RowDefinitions.Add(new RowDefinition());
grid1.SetValue(Grid.RowProperty, r);
grids.Children.Add(button1);
grids.Children.Add(text1);
r = r + 1;
}
EDIT
int r =0;
private void button2_Click(object sender, RoutedEventArgs e)
{
db obj = new db();
var query = from p in obj.TableA select p ;
foreach(var a in query.ToList())
{
TextEdit text1; Button button1; Grid grid1;
grids.RowDefinitions.Add(new RowDefinition());
text1 = new TextEdit();
text1.SetValue(Grid.ColumnProperty, 1);
text1.SetValue(Grid.RowProperty, r);
button1 = new Button();
button1.Content = a.name;
button1.Click += new RoutedEventHandler(button1_Click);
button1.SetValue(Grid.ColumnProperty, 1);
button1.SetValue(Grid.RowProperty, r);
grid1 = new Grid();
grid1.SetValue(Grid.ColumnProperty, 1);
grids.RowDefinitions.Add(new RowDefinition());
grid1.SetValue(Grid.RowProperty, r);
grids.Children.Add(button1);
grids.Children.Add(text1);
r = r + 1;}
}

Ok. Delete all your code and start all over.
If you're working with WPF, you really need to have The WPF Mentality
As a general rule, you almost never create or manipulate UI elements in procedural code in WPF.
That's what XAML is for.
This the right way to do what you're asking in WPF (in a full working example):
<Window x:Class="MiscSamples.ItemsControlSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
Title="ItemsControlSample" Height="300" Width="300">
<DockPanel>
<Button Content="Add New Row" Command="{Binding AddNewRowCommand}"
DockPanel.Dock="Bottom"/>
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" Background="Gainsboro" BorderThickness="1" Margin="2">
<!-- This is the Inner Grid for each element, which is represented in Brown color in your picture -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width=".2*"/>
<ColumnDefinition Width=".2*"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding Label1Text}"
Margin="2"/>
<Button Content="Button1"
Command="{Binding DataContext.Command1, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
Grid.Column="1" Margin="2"/>
<Button Content="Button2"
Command="{Binding DataContext.Command2, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
Grid.Column="2" Margin="2"/>
<dxe:TextEdit Text="{Binding Text}"
Grid.Row="1" Grid.ColumnSpan="3"
Margin="2"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer CanContentScroll="True">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>
</Window>
Code Behind:
public partial class ItemsControlSample : Window
{
public ItemsControlSample()
{
InitializeComponent();
DataContext = new ItemsControlSampleViewModel();
}
}
ViewModel:
public class ItemsControlSampleViewModel
{
public ObservableCollection<ItemsControlSampleData> Data { get; set; }
public Command AddNewRowCommand { get; set; }
public Command<ItemsControlSampleData> Command1 { get; set; }
public Command<ItemsControlSampleData> Command2 { get; set; }
public ItemsControlSampleViewModel()
{
var sampledata = Enumerable.Range(0, 10)
.Select(x => new ItemsControlSampleData()
{
Label1Text = "Label1 " + x.ToString(),
Text = "Text" + x.ToString()
});
Data = new ObservableCollection<ItemsControlSampleData>(sampledata);
AddNewRowCommand = new Command(AddNewRow);
Command1 = new Command<ItemsControlSampleData>(ExecuteCommand1);
Command2 = new Command<ItemsControlSampleData>(ExecuteCommand2);
}
private void AddNewRow()
{
Data.Add(new ItemsControlSampleData() {Label1Text = "Label 1 - New Row", Text = "New Row Text"});
}
private void ExecuteCommand1(ItemsControlSampleData data)
{
MessageBox.Show("Command1 - " + data.Label1Text);
}
private void ExecuteCommand2(ItemsControlSampleData data)
{
MessageBox.Show("Command2 - " + data.Label1Text);
}
}
Data Item:
public class ItemsControlSampleData
{
public string Label1Text { get; set; }
public string Text { get; set; }
}
Helper classes:
public class Command : ICommand
{
public Action Action { get; set; }
public string DisplayName { get; set; }
public void Execute(object parameter)
{
if (Action != null)
Action();
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled = true;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action action)
{
Action = action;
}
}
public class Command<T>: ICommand
{
public Action<T> Action { get; set; }
public void Execute(object parameter)
{
if (Action != null && parameter is T)
Action((T)parameter);
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled = true;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action<T> action)
{
Action = action;
}
}
Result:
Notice how I'm not dealing with UI in procedural code, but instead I'm using DataBinding and simple, simple properties. That's how you program in WPF. That's what the WPF mentality is about.
I'm using an ItemsControl and a DataTemplate defined in XAML to let WPF create the UI for each of my data items.
Also notice how my code does nothing except expose the data and define reusable Commands that serve as abstractions to the user actions such as Button clicks. This way you can concentrate in coding your business logic instead of struggling with how to make the UI work.
The buttons inside each item are bound to the Commands using a RelativeSource Binding to navigate upwards in the Visual Tree and find the DataContext of the ItemsControl, where the Commands are actually defined.
When you need to add a new item, you just add a new item to the ObservableCollection that contains your data and WPF automatically creates the new UI elements bound to that.
Though this might seem like "too much code", most of the code I posted here is highly reusable and can be implemented in a Generic ViewModel<T> that is then reusable for any type of data items. Command and Command<T> are also write-once reusable classes that can be found in any MVVM framework such as Prism, MVVM Light or Caliburn.Micro.
This approach is really much preferred in WPF, because it enables a great amount of scalability and independence between the UI and the business logic, and it also enables testability of the ViewModel.
I suggest you read all the materials linked in the post, most importantly Rachel's WPF Mentality and related blog posts. Let me know if you need further help.
WPF Rocks. Just copy and paste my code in a File -> New Project -> WPF Application and see the results for yourself.

It's actually much easier in behind code then in xaml code..
My Xaml code:
<Window x:Class="WpfAddGridWithStackPanel.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 x:Name="Grid_Grid" Margin="0,0,0,32">
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid x:Name="Grid_Grid" Margin="0,0,0,32"/>
</ScrollViewer>
<Button x:Name="btn_Add" Height="32" DockPanel.Dock="Bottom" VerticalAlignment="Bottom" Content="Add New Row" Click="btn_Add_Click" Width="150" HorizontalAlignment="Left" UseLayoutRounding="True" />
<Button x:Name="btn_Remove" Height="32" DockPanel.Dock="Bottom" VerticalAlignment="Bottom" Content="Remove last Row" Click="btn_Remove_Click" Width="150" HorizontalAlignment="Right" />
</Grid>
</Window>
And Code behind:
public partial class MainWindow : Window
{
int num = 0;
public MainWindow()
{
InitializeComponent();
}
void btn1_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
void btn2_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
private void btn_Remove_Click(object sender, RoutedEventArgs e)
{
try
{
Grid_Grid.RowDefinitions.RemoveAt(Grid_Grid.RowDefinitions.Count - 1);
Grid_Grid.Children.RemoveAt(Grid_Grid.Children.Count - 1);
num--;
}
catch { }
}
private void btn_Add_Click(object sender, RoutedEventArgs e)
{
StackPanel stack = new StackPanel();
DockPanel dock = new DockPanel();
Label lbl = new Label();
Button btn1 = new Button();
Button btn2 = new Button();
TextBox txt1 = new TextBox();
stack.Children.Add(dock);
stack.Children.Add(txt1);
dock.Children.Add(lbl);
dock.Children.Add(btn2);
dock.Children.Add(btn1);
#region StackPanel Properties
stack.Background = Brushes.LightGray;
#endregion
#region DockPanel Content Properties
lbl.Content = "Label " + (num + 1).ToString();
lbl.Height = 32;
lbl.Width = 100;
lbl.FontSize = 12;
lbl.SetValue(DockPanel.DockProperty, Dock.Left);
lbl.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
btn1.Content = "Butten 1";
btn1.Height = 32;
btn1.Width = 100;
btn1.FontSize = 12;
btn1.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
btn1.SetValue(DockPanel.DockProperty, Dock.Right);
btn1.Click += new RoutedEventHandler(btn1_Click);
btn2.Content = "Butten 2";
btn2.Height = 32;
btn2.Width = 100;
btn2.FontSize = 12;
btn2.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
btn2.SetValue(DockPanel.DockProperty, Dock.Right);
btn2.Click += new RoutedEventHandler(btn2_Click);
#endregion
#region TextBox Properties
txt1.Text = "Text " + (num + 1).ToString();
txt1.Height = 32;
txt1.Width = double.NaN;
txt1.FontSize = 12;
txt1.Padding = new Thickness(0, 7, 0, 7);
#endregion
Grid_Grid.RowDefinitions.Add(new RowDefinition());
Grid_Grid.RowDefinitions[num].Height = new GridLength(66, GridUnitType.Pixel);
Grid_Grid.Children.Add(stack);
stack.SetValue(Grid.RowProperty, num);
num++;
}
}

Related

INotifyPropertyChanged in wpf application of List

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.

Oxyplot throw exception when I add so many graphs

I want to drow so many graphs with OxyPlot Library.
And I'm testing now that I can add how many graphs with dynamic (but I'll not add graphs over 10000 graphs because it's max graphs in real application).
However when I'll add over 200 graphs, the Oxyplot throw exception.
Exception message is "This PlotModel is already in use by some other PlotView control.".
There are all of my code. (In code, I add graph with dynamic and I add values to the all graphs each 5 second in other thread.)
//Xaml -- MainView
<Window x:Class="OxyplotStressTest.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:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
xmlns:local="clr-namespace:OxyplotStressTest"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="725">
<Grid>
<Button Content="Add 100" HorizontalAlignment="Left" Height="32" Margin="20,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click100"/>
<Button Content="Add 50" HorizontalAlignment="Left" Height="32" Margin="102,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click50"/>
<Button Content="Add 10" HorizontalAlignment="Left" Height="32" Margin="189,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click10"/>
<Button Content="Add 1" HorizontalAlignment="Left" Height="32" Margin="274,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click1"/>
<Grid Margin="20,65,19,10">
<ScrollViewer>
<ItemsControl ItemsSource="{Binding List}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Tag}"/>
<oxy:PlotView HorizontalAlignment="Left" Height="130" Margin="20,23,0,0" VerticalAlignment="Top" Width="600"
Model="{Binding Chart}" IsMouseWheelEnabled="False" IsManipulationEnabled="False" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
//C# -- MainWindow.cs
public partial class MainWindow : Window
{
private MainWindowViewModel mMainWindowViewModel = null;
public MainWindow()
{
InitializeComponent();
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
this.DataContext = mainWindowViewModel;
mMainWindowViewModel = mainWindowViewModel;
Thread thread = new Thread(new ParameterizedThreadStart(reloadGraph));
thread.Start();
}
private void Button_Click100(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(100);
}
private void Button_Click50(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(50);
}
private void Button_Click10(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(10);
}
private void Button_Click1(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(1);
}
private void reloadGraph(object param)
{
while (true)
{
Thread.Sleep(5000);
if (mMainWindowViewModel.List.Count > 0)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.reloadGraph();
}
Console.WriteLine(Environment.WorkingSet.ToString());
}
}
}
//C# -- MainViewModel
public MainWindowViewModel()
{
listVal = new ObservableCollection<Items>();
BindingOperations.EnableCollectionSynchronization(this.listVal, new object());
}
private ObservableCollection<Items> listVal = new ObservableCollection<Items>();
public ObservableCollection<Items> List
{
get
{
return listVal;
}
set
{
listVal = value;
NotifyPropertyChanged("List");
}
}
public class Items
{
public string Tag { get; set; }
private PlotModel chartVal = new PlotModel();
public PlotModel Chart
{
get
{
return chartVal;
}
set
{
chartVal = value;
}
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
//C# -- Model Class
class AddGraph
{
private MainWindowViewModel mMainWindowViewModel = null;
public AddGraph(MainWindowViewModel pMainWindowViewModel)
{
mMainWindowViewModel = pMainWindowViewModel;
}
public void addGraph(int pCount)
{
try
{
for (int i = 0; i < pCount; i++)
{
Random random = new Random();
long data = random.Next(100);
ColumnSeries column = new ColumnSeries();
column.FillColor = OxyColors.SkyBlue;
column.Items.Add(new ColumnItem() { Value = data });
data *= random.Next(50);
column.Items.Add(new ColumnItem() { Value = data });
Items items = new Items();
items.Tag = mMainWindowViewModel.List.Count.ToString();
items.Chart.Series.Add(column);
items.Chart.InvalidatePlot(true);
mMainWindowViewModel.List.Add(items);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public void reloadGraph()
{
try
{
List<Items> newList = new List<Items>();
foreach (Items listItem in mMainWindowViewModel.List)
{
string tag = listItem.Tag;
PlotModel plotModel = listItem.Chart;
ColumnSeries oldGraph = (ColumnSeries)plotModel.Series[0];
ColumnSeries newGraph = new ColumnSeries();
newGraph.FillColor = OxyColors.SkyBlue;
for (int i = 0; i < oldGraph.Items.Count; i++)
{
if (oldGraph.Items.Count == 30 && i == 0)
{
continue;
}
newGraph.Items.Add(new ColumnItem() { Value = oldGraph.Items[i].Value });
}
Random random = new Random();
long val = random.Next(500);
val *= random.Next(50);
newGraph.Items.Add(new ColumnItem() { Value = val });
Items items = new Items();
items.Tag = tag;
items.Chart.Series.Add(newGraph);
items.Chart.InvalidatePlot(true);
newList.Add(items);
}
#region //there are my solution and it shows good performance
int index = 0;
foreach (var addItem in newList)
{
mMainWindowViewModel.List[index] = addItem;
index++;
}
#endregion
#region //there are my first code and it has problem
mMainWindowViewModel.List.Clear();
foreach (var addItem in newList)
{
mMainWindowViewModel.List.Add(addItem);
}
#endregion
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Maybe my code is bad, but I don't know where is the bad code because it dosen't stop on BreakPoint.
If you give me a advice, I'm so glad.
I think you may need to rebuild it a little using idea from OxyPlot Example: https://github.com/oxyplot/oxyplot/tree/develop/Source/Examples/WPF/WpfExamples
When i were working last months with oxyplots i found out that this official examples are well done with they ideas, they solution with Performance Demo using this virtualization may helps with performance:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsVirtualizing="True" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
The problem may cause using NotifyPropertyChange as refreshing UI as adding new chart maybe you should somehow Unbind List > Notify > Bind New List.
Check more in the link and try to mash-ups they solution to make your own :)
I glad if i have helped some :)

How can I get nice animations in a ListView when an ObservableCollection gets sorted on UWP?

I cant get nice reorder animation in ListView - also tried overriding all the various internal transitions via the <Transitions><TransitionsCollection>... property. Nothing. Tried using simple .Insert/.Remove and .Move and neither works nicely.
Insert/Remove has animation for the items that happen to have been pushed around and .Move acts like a Reset on the collection.
The following code in MainPage:
public sealed partial class MainPage : Page
{
private ObservableCollection<Holder> Items = new ObservableCollection<Holder>(Enumerable.Range(0, 10).Select(x => new Holder(x)));
public MainPage()
{
this.InitializeComponent();
Items.CollectionChanged += Items_CollectionChanged;
}
private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
}
private Random _random = new Random();
private bool asc = true;
private void Button_Click(object sender, RoutedEventArgs e)
{
IList<Holder> temp;
//var temp = Items.Skip(1).Union(Items.Take(1)).ToList();
// var temp = new Holder[] { Items.ElementAt(Items.Count - 1) }.Union(Items.Take(Items.Count - 1)).ToList();
temp = Items.OrderBy(x => _random.NextDouble()).ToList();
// temp = asc ? Items.OrderBy(x => x.I).ToList() : Items.OrderByDescending(x => x.I).ToList();
asc = !asc;
for (int i = 0; i < temp.Count; i++)
{
if (Items[i] != temp[i])
{
// When using Move, no animation occurs at all. When using Remove/Insert, there's partial
// animation for the items that happened to stay at the same place.
//Items.Move(Items.IndexOf(temp[i]), i);
Items.Remove(temp[i]);
Items.Insert(i, new Holder(temp[i].I));
}
}
}
}
public class Holder
{
public Holder(int i)
{
I = i;
}
public string Name => "Hey hey hey " + I.ToString();
public int I { get; private set; }
public override bool Equals(object obj)
{
return ((Holder)obj).I == I;
}
public override int GetHashCode()
{
return I.GetHashCode();
}
}
With the following XAML:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Content="Mix" Click="Button_Click" Grid.Row="1"></Button>
<ListView ItemsSource="{x:Bind Items}" >
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderThickness="3" BorderBrush="Blue">
<TextBlock Text="{Binding Name}" Margin="20"/>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

wp8 public string is not wrapping in programatically created Text Block

Hi Guys I'm working on Windows Phone 8 application. Here I got problem in wrapping text Block text.
When my string array was not public then wrapping is working fine, while when I created my string array public then wrapping does not work...!
I am not able to find my error.
My code is here
int a =1;
ScrollViewer scroll = new ScrollViewer();
string[] questions = new string[]
{ "Question :\n What is OOPS? \n\n Answer: \n Object-oriented programming (OOP) is a programming paradigm based on the concept of objects which are data structures that contain data in the form of fields often known as attributes and code in the form of procedures often known as methods. There are a few principle concepts that form the foundation of object-oriented programming: 1- Object \n 2- Class \n 3- Abstraction \n 4- Polymorphism \n 5- Inheritance \n 6- Encapsulation \n 7- Overloading & OverRiding "
};
int i;
private void showContent()
{
Grid ContentPanel = new Grid();
ContentPanel.Height = 400;
ContentPanel.Width = 440;
ContentPanel.Margin = new Thickness(0, 20, 0, 0);
scroll.Height = 400;
scroll.Width = 440;
scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
TextBlock text_question = new TextBlock();
text_question.Height = Double.NaN;
text_question.Width = 420;
// text_question.Text = "Arsal Are you going.? If user is not login then there at detail page user want to add product in his wish list then there is popup comes .... Please Login There should be align text. when user goes to detail screen then first show batch 42 % off after that shows 0% off. more share button and like button alignment also changes slowly. user can identify easily.";
text_question.TextWrapping = TextWrapping.Wrap;
text_question.Margin = new Thickness(10, 10, 10, 10);
scroll.Content = questions[0];
ContentPanel.Children.Add(scroll);
//scroll.Content = questions[i];
TitlePanel.Children.Add(ContentPanel);
}
text_question.Text = ""; which is commented in this function is wrapping while the public string doesn't wrap.
I want to use string out side any function then string have to public.
private void next_click(object sender, RoutedEventArgs e)
{
// MessageBox.Show("Here is Next Question");
a = a + 1;
count.Text = a.ToString();
if (a > 1)
{
previous.IsEnabled = true;
}
if (a == 5)
{
next.IsEnabled = false;
}
if (i >= 0 && i < questions.Length)
{
i = i + 1;
scroll.Content = questions[i];
}
}
Looking at the code you posted here, the issue appears to be that you are never adding the TextBlock with the wrapping property set to the ScrollViewer. I would update this line:
scroll.Content = questions[0];
to:
scroll.Content = text_question;
and then manipulate text_question's content in the click event handlers.
That being said, I think you're making this far more complicated than it needs to be and making your UI code more complicated than necessary. I honestly can't think of a time that I've ever had a need to create UI controls in code and add them to the Children collection. Generally speaking, Windows Phone uses the MVVM pattern and your UI layout should be done via binding.
In this case, I'd do something like the following:
public class QuestionModel : INotifyPropertyChanged
{
private string[] _questions = new string[]
{
"Question :\n What is OOPS? \n\n Answer: \n Object-oriented programming (OOP) is a programming paradigm based on the concept of objects which are data structures that contain data in the form of fields often known as attributes and code in the form of procedures often known as methods. There are a few principle concepts that form the foundation of object-oriented programming: 1- Object \n 2- Class \n 3- Abstraction \n 4- Polymorphism \n 5- Inheritance \n 6- Encapsulation \n 7- Overloading & OverRiding ",
"Question 2",
"Question 3",
"Question 4"
};
private int _selectedIndex = 0;
public QuestionModel() {
PrevCommand = new DelegateCommand(() => {
if(_selectedIndex > 0) {
_selectedIndex--;
selectedIndexChanged();
}
});
NextCommand = new DelegateCommand(() => {
if(_selectedIndex < _questions.Length - 1) {
_selectedIndex++;
selectedIndexChanged();
}
});
}
private void selectedIndexChanged() {
NotifyPropertyChanged("CurrentQuestion");
NotifyPropertyChanged("QuestionText");
NotifyPropertyChanged("IsNextEnabled");
NotifyPropertyChanged("IsPrevEnabled");
}
public int CurrentQuestion
{
get { return _selectedIndex + 1; }
}
public string QuestionText
{
get { return _questions[_selectedIndex]; }
}
public bool IsNextEnabled
{
get { return _selectedIndex < _questions.Length - 1; }
}
public bool IsPreviousEnabled
{
get { return _selectedIndex > 0; }
}
private ICommand _nextCommand;
public ICommand NextCommand
{
get { return _nextCommand; }
set
{
_nextCommand = value;
NotifyPropertyChanged();
}
}
private ICommand _prevCommand;
public ICommand PrevCommand
{
get { return _prevCommand; }
set
{
_prevCommand = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class DelegateCommand : ICommand
{
private readonly Action _action;
public DelegateCommand(Action action)
{
_action = action;
}
public void Execute(object parameter)
{
_action();
}
public bool CanExecute(object parameter)
{
return true;
}
#pragma warning disable 67
public event EventHandler CanExecuteChanged;
#pragma warning restore 67
}
Then in the XAML, I'd have the following:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.DataContext>
<local:QuestionModel/>
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="Question" Text="{Binding QuestionText}"/>
</ScrollViewer>
<TextBlock x:Name="Count" Grid.Row="1" Margin="10,10,10,0" Text="{Binding CurrentQuestion, Mode=OneWay}">
</TextBlock>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button x:Name="previous" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" Content="Previous" IsEnabled="{Binding IsPreviousEnabled}" Command="{Binding PrevCommand}"></Button>
<Button x:Name="next" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" Content="Next" IsEnabled="{Binding IsNextEnabled}" Command="{Binding NextCommand}"></Button>
</Grid>
</Grid>
</Page>
This way, there is no code in the code behind and you don't have to programatically create controls or modify the content. You just let the framework's data binding do the work for you and your model doesn't need to know how the UI puts everything together and vice versa.

Scroller-like animation on a Label in WPF

I have a simple app where after clicking a button the value of a label is updated every second.I'm doing this as a POC for a progress bar control that I want to develop.
I would like to know if there is a way to apply some kind of scroller animation to the label which will:
1) When the content of a label is updated it will scroll the new value from the top and the old one will be scrolled down and disappear from view(Hope this makes sence).
I know that this could probably be achieved with some kind of animation but I couldn't find any helpful examples on the web if anyone knows how this can be done please share your expertise:
View:
<Window x:Class="WpfApplication1.ScrollerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Scroller" DataContext="{StaticResource scrollerVM}" Height="150" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Messages}" Width="200" Height="50" BorderThickness="0" VerticalAlignment="Top" HorizontalAlignment="Left">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Text}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
<Button Width="70" Height="24" Content="Add new" Command="{Binding AddNew}" HorizontalAlignment="Left" Margin="0,56,0,30" />
</Grid>
</Window>
View model:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Threading;
namespace WpfApplication1.Scroller
{
public class Message
{
public Message(string _text)
{
text = _text;
}
private string text;
public string Text
{
get { return text; }
set {text = value;}
}
}
public class ScrollerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public DelegateCommand AddNew { get; protected set; }
ObservableCollection<Message> _messages = new ObservableCollection<Message>();
public ObservableCollection<Message> Messages
{
get { return _messages; }
set
{
_messages = value;
OnPropertyChanged("Messages");
}
}
public ScrollerViewModel()
{
AddNew = new DelegateCommand(Add);
}
private void Add(object parameter)
{
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += new System.EventHandler(timer_Tick);
timer.Interval = new System.TimeSpan(0, 0, 1);
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
Messages.Clear();
Messages.Add(new Message(DateTime.Now.ToString("ss")));
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
More comprehensive/different examples here.
The following will result in a basic vertical marquee (scrolling text block).
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Loaded="Window_Loaded">
<Canvas Name="canvas1" >
<TextBlock Name="textBlock1">Hello</TextBlock>
</Canvas>
</Window>
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void BeginAnimation()
{
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = -textBlock1.ActualHeight;
doubleAnimation.To = canvas1.ActualHeight;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(3));
textBlock1.BeginAnimation(Canvas.TopProperty, doubleAnimation);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BeginAnimation();
}
}
First, you'll want "smooth scrolling" on the ListBox:
ScrollViewer.CanContentScroll="False"
Then, you could create a custom Attached Property to specify the vertical offset you want to scroll. Then create a custom Behavior that hooks up to the ListBox's ItemsSource's "ItemsSourceChanged" event, which would fire off an animation that you can define inside the behavior. That should at least be a start. I'm not sure what the specific animation would be...some DoubleAnimation using a calculation of your offset plus new item's height.

Categories

Resources