How to dispose Image in WPF - c#

I create a list and set it's datatemplete as Image.
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="411" Margin="45,24,0,0" VerticalAlignment="Top" Width="336">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ImgSource}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
then I load 100 pictures
public partial class MainWindow : Window
{
List<test> lstTest = new List<test>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 100; i++)
{
test t = new test();
t.ImgSource = #"d:\test\1.jpg";
lstTest.Add(t);
}
}
private void btnHead_Click(object sender, RoutedEventArgs e)
{
listBox.ItemsSource = lstTest;
}
private void btnClear_Click(object sender, RoutedEventArgs e)
{
lstTest = null;
listBox.ItemsSource = null;
}
public class test
{
public string ImgSource { get; set; }
}
}
before I click btnHead,the mem is 20m, and when I click this button, the mem increase to 40m.
I want to create a function to release mem (return 20m), but btnClear_Click do not work.
How to dispose Image in wpf?

Related

I want add item to tabcontrol with dynamic

I'm making a WPF Application with MVVM pattern.
It's that I click a button many times and if I click Subbutton, it shows SubWindow with many Tabs.
Tab count is the same to click times.
But I want contain items in one Tab.
And click times is not the same always.
How should edit my code?
//view
<Grid>
<Button Content="CountUp" HorizontalAlignment="Left" Height="76" Margin="72,57,0,0" VerticalAlignment="Top" Width="135" Click="OnClickCountUp"/>
<Button Content="OpenSubWindow" HorizontalAlignment="Left" Height="74" Margin="269,202,0,0" VerticalAlignment="Top" Width="123" Click="OnClicOpenSubWindow"/>
<Label Content="Count : " HorizontalAlignment="Left" Height="28" Margin="254,73,0,0" VerticalAlignment="Top" Width="53"/>
<Label Content="{Binding CountVal}" HorizontalAlignment="Left" Height="28" Margin="307,73,0,0" VerticalAlignment="Top" Width="67"/>
</Grid>
//ViewModel
public class MainViewModel : INotifyPropertyChanged
{
private string count;
public string CountVal
{
get { return count; }
set
{
count = value;
NotifyPropertyChanged("CountVal");
}
}
public ObservableCollection<TabItemData> TabItems { get; set; } = new ObservableCollection<TabItemData>();
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
public class TabItemData
{
public string Header { get; set; }
public ObservableCollection<CheckBox> Content { get; set; }
}
//Codebehind
public partial class MainWindow : Window
{
private MainViewModel mViewmodel;
int count = 0;
public MainWindow()
{
InitializeComponent();
mViewmodel = new MainViewModel();
this.DataContext = mViewmodel;
}
private void OnClicOpenSubWindow(object sender, RoutedEventArgs e)
{
Window1 window1 = new Window1(mViewmodel);
window1.Show();
}
private void OnClickCountUp(object sender, RoutedEventArgs e)
{
count++;
ObservableCollection<CheckBox> items = new ObservableCollection<CheckBox>();
for (int i = 0; i <= count; i++)
{
CheckBox checkBox = new CheckBox();
checkBox.IsChecked = false;
checkBox.Content = count.ToString();
items.Add(checkBox);
}
mViewmodel.CountVal = count.ToString();
mViewmodel.TabItems.Add(new TabItemData() { Header = count.ToString(), Content = items });
}
}
//SubWindow's View
<Grid>
<TabControl ItemsSource="{Binding TabItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<CheckBox Content="{Binding Content}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
//SubWindow's Codebehind
public partial class Window1 : Window
{
public Window1(MainViewModel pMainViewModel)
{
InitializeComponent();
this.DataContext = pMainViewModel;
}
}
And there are supplements.
#I want use the checkbox as item in Tab. So I don't want change as possibly.
#If I can, I want add Tabs each 5 items. If you give me with that code, I'm very glad. (For Example, page1 contains item1, 2, 3, 4 and 5. page2 contains item6, 7... and so on.)

Window1 does not contain definition

I've got code where there's a string variable in MainWindow called "repeatNumber" - there's also two buttons in MainWindow. btn2 should open up a new window 'otherwindow' that has the repeatNumber string in it and displays the picture.
'Window1' does not contain a definition for 'getRepeatedNumber' and no extension method 'getRepeatedNumber' accepting a first argument of type 'Window1' could be found.
Can anyone help me with this? Can this be fixed without using MVVM? Code bellow:
Mainwindow.cs
public partial class MainWindow : Window
{
private string repeatNumber;
public MainWindow()
{
InitializeComponent();
string[] assignments = new string[] { "https://cdn2.iconfinder.com/data/icons/animals/48/Turtle.png", "https://cdn2.iconfinder.com/data/icons/animals/48/Butterfly.png", "https://cdn2.iconfinder.com/data/icons/animals/48/Dolphin.png", "https://cdn2.iconfinder.com/data/icons/animals/48/Elephant.png", "https://cdn2.iconfinder.com/data/icons/animals/48/Hippopotamus.png", "https://cdn2.iconfinder.com/data/icons/animals/48/Panda.png" };
Random rnd = new Random();
string[] randomingArray = assignments.OrderBy(x => rnd.Next()).ToArray();
List<Images> animals = new List<Images>();
for (int i = 1; i < 100; i++)
{
if (i == 9)
{
repeatNumber = randomingArray[i % randomingArray.Length];
animals.Add(new Images() { Source = repeatNumber, Number = i });
}
else if ((i % 9) == 0)
{
animals.Add(new Images() { Source = repeatNumber, Number = i });
}
else
{
animals.Add(new Images() { Source = randomingArray[i % rnd.Next(1, 5)], Number = i });
}
ItemsControl1.ItemsSource = animals;
}
}
private void btn1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("test");
}
private void btn2_Click(object sender, RoutedEventArgs e)
{
Window1 otherwindow = new Window1();
otherwindow.Show();
string value = otherwindow.getRepeatedNumber; <--- This line gives me the error
}
}
class Images
{
public int Number { get; set; }
public string Source { get; set; }
}
Mainwindow.xaml
<Grid>
<ListBox x:Name="ItemsControl1">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5">
</UniformGrid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="3" Width="Auto" Height="Auto">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Number}"/>
<Image Source="{Binding Source}" Margin="0,0,5,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid>
<Button x:Name="btn1" Click="btn1_Click" Height="20" VerticalAlignment="Bottom" Margin="127,0,316,0" Content="Instruction"></Button>
<Button x:Name="btn2" Click="btn2_Click" Height="20" VerticalAlignment="Bottom" Margin="300,0,109,0" Content="Results" Width="74"></Button>
</Grid>
</Grid>
Window1.cs
public class Window2 : Window
{
public string getRepeatedNumber { get; set; }
public Window2(string repeatNumber)
{
getRepeatedNumber = repeatNumber;
}
}
and Window1.xaml is just
<Grid>
</Grid>

DataGrid generates empty rows

I have two threads - let's name them Calc thread and UI thread. Inside the Calc thread I refreshes an ObservableCollection. I also have a handler for the CollectionCHanged event of the ObservableCollection. As I know, the handler executes within the same thread that raises the CollectionChanged event - so that is the same thread that refreshes the ObservableCollection in my case. So, to refresh UI I can't use bindings directly as in single-threaded application - UI must be refreshed manually through Dispatcher. But when I use DataGrid in the UI I get the empty rows instead of any data, and when I use ListBox, for example, the appropriate data is showed:
data grid case to the left, list box case to the right
(list box is just for example that the data binds and shows; I don't want the data to be showed like in this list box, but like in data grid (if it worked as I expect - not as in case on the picture) - table with column titles)
Well, I prepared the code, which you can copy and paste to reconstruct the problem:
C#
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading;
using System.Windows;
namespace WpfApplication1
{
public class MyClass
{
public int Integer { get; set; }
public string Str { get; set; }
}
public partial class MainWindow : Window
{
public ObservableCollection<MyClass> MyCollection { get; set; }
public MainWindow()
{
InitializeComponent();
MyCollection = new ObservableCollection<MyClass>();
MyCollection.CollectionChanged += MyCollection_CollectionChanged;
Thread t = new Thread(new ThreadStart(() =>
{
for (int i = 0; i < 10; i++)
{
MyCollection.Add(new MyClass()
{
Integer = i,
Str = "String" + i
});
Thread.Sleep(500);
}
}));
t.Start();
}
void MyCollection_CollectionChanged(
object sender,
NotifyCollectionChangedEventArgs e)
{
Dispatcher.Invoke(
() =>
{
foreach (var item in e.NewItems)
dataGrid.Items.Add((MyClass)item);
});
}
}
}
XAML (just comment/uncomment the list box case and the data grid case):
<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" Height="350" Width="525">
<Grid>
<!--<ListBox Name="dataGrid">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Integer}" />
<TextBlock Text="{Binding Path=Str}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>-->
<DataGrid Name="dataGrid">
<DataGrid.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Integer}" />
<TextBlock Text="{Binding Path=Str}" />
</StackPanel>
</DataTemplate>
</DataGrid.ItemTemplate>
</DataGrid>
</Grid>
</Window>
Is this what you want?
C#
namespace WpfApplication1
{
public class MyClass
{
public int Integer { get; set; }
public string Str { get; set; }
}
public partial class MainWindow : Window
{
public ObservableCollection<MyClass> MyCollection { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyCollection = new ObservableCollection<MyClass>();
Thread t = new Thread(new ThreadStart(() =>
{
for (int i = 0; i < 10; i++)
{
Dispatcher.Invoke(new Action(() =>
{
MyCollection.Add(new MyClass()
{
Integer = i,
Str = "String " + i
});
}));
}
}));
t.Start();
}
}
}
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" Height="350" Width="525">
<Grid>
<DataGrid Name="dataGrid" ItemsSource="{Binding MyCollection}">
<DataGrid.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Integer}" />
<TextBlock Text="{Binding Str}" />
</StackPanel>
</DataTemplate>
</DataGrid.ItemTemplate>
</DataGrid>
</Grid>
</Window>
Other method is to use another List:
public partial class MainWindow : Window
{
private List<MyClass> _MyCollection;
public ObservableCollection<MyClass> MyCollection { get; set; }
private DispatcherTimer dispatcherTimer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyCollection = new ObservableCollection<MyClass>();
_MyCollection = new List<MyClass>();
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
Thread t = new Thread(new ThreadStart(() =>
{
for (int i = 0; i < 10; i++)
{
_MyCollection.Add(new MyClass()
{
Integer = i,
Str = "String " + i
});
Thread.Sleep(500);
}
}));
t.Start();
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (_MyCollection.Count != MyCollection.Count)
{
MyCollection.Add(_MyCollection[_MyCollection.Count - 1]);
}
}
}
Second edit with you example:
namespace WpfApplication1
{
public class MyClass
{
public int Integer { get; set; }
public string Str { get; set; }
}
public partial class MainWindow : Window
{
private ObservableCollection<MyClass> _MyCollection;
public ObservableCollection<MyClass> MyCollection { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyCollection = new ObservableCollection<MyClass>();
_MyCollection = new ObservableCollection<MyClass>();
_MyCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(_MyCollection_CollectionChanged);
Thread t = new Thread(new ThreadStart(() =>
{
for (int i = 0; i < 10; i++)
{
_MyCollection.Add(new MyClass()
{
Integer = i,
Str = "String " + i
});
Thread.Sleep(500);
}
}));
t.Start();
}
private void _MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Dispatcher.Invoke(new Action(
() =>
{
foreach (var item in e.NewItems)
MyCollection.Add((MyClass)item);
}));
}
}
}

Column from selected Datagrid

I have code that returns me the selected row from a datagrid.
Now i want to have the value of the 3th column.
The code I have below already gives me the selected row
private void BandGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
var row_list = GetDataGridRows(BandGrid);
foreach (DataGridRow single_row in row_list)
{
if (single_row.IsSelected == true)
{
}
}
}
catch { }
}
Assuming that your DataGrid has an underlying data structure and you are not using datagridview, each row represents an object usually in a list of objects. You can just cast the selected row to the object's Type and pull the field of the cell you want. Also you don't have to loop through each one in the list. SelectedItem will have what you want.
Edited
private void BandGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Band single_row = (Band)BandGrid.SelectedItem;
string cellValue = single_row.Picture;
}
Edited End
If you have multi select feature on you may need to pull all iterating through SelectedItems. Note: don't make changes to the items in the foreach loop this will cause errors. You will need to make a copy of the data if you need to change the data.
private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
listCells = new List<string>();
foreach(MyClass single_row in BandGrid.SelectedItems)
{
//do something with the object
listCells.add( single_row.Picture);
}
}
Example program. This sets the DataSource for the grid to List<MyClass> and every time the selection is changed textbox1 displays data in column c from the selected row.
public partial class MainWindow : Window
{
public class MyClass
{
public int a { get; set; }
public int b { get; set; }
public int c { get; set; }
public int d { get; set; }
}
public MainWindow()
{
InitializeComponent();
MyClass obj;
List<MyClass> bind = new List<MyClass>();
for (int i = 0; i < 10; i++)
{
obj = new MyClass();
obj.a = i;
obj.b = 2*i;
obj.c = 3*i;
obj.d = 4*i;
bind.Add(obj);
}
dataGrid1.ItemsSource = bind;
}
private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
textBox1.Text = ((MyClass)dataGrid1.SelectedItem).c.ToString();
}
}
Here's the xaml
<Window x:Class="yo.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>
<DataGrid AutoGenerateColumns="True" Height="200" HorizontalAlignment="Left" Margin="116,116,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="344" SelectionChanged="dataGrid1_SelectionChanged" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="87,41,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
</Grid>
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
var selectedValue = GridView1.SelectedRow.Cells[2].Text;
}

How to add/move multiselected items from one listbox to another listbox?

I have a small prototype that allows to add selected item from one listbox to another. I need to be able to select multiple item from listbox and move them to another and backward - from second listbox to first one. I am wondering if someone has good sample or can modify the code I already have. Thank you in advance.
Two listboxes and buttons XAML:
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Margin="0,40,225,20">
<ListBox x:Name="LeftListBox" SelectionMode="Multiple"/>
</Border>
<Border Margin="0,40,20,20" BorderThickness="1" BorderBrush="#FFCECECE" HorizontalAlignment="Right" Width="169" Padding="5" >
<ListBox x:Name="RightListBox" BorderThickness="0" />
</Border>
<Button x:Name="AddButton" Height="40" Margin="0,3,198,0" VerticalAlignment="Center" Click="AddButton_Click" HorizontalAlignment="Right" Width="15" Content="▶" />
<Button x:Name="RemoveButton" Height="40" Margin="0,94,198,0" VerticalAlignment="Center" Click="RemoveButton_Click" HorizontalAlignment="Right" Width="15" Content="R" />
</Grid>
Code behind:
public partial class SelectServersUC : UserControl
{
private ArrayList myDataList = null;
string currentItemText ;
int currentItemIndex ;
public SelectServersUC()
{
this.InitializeComponent();
myDataList = LoadListBoxData();
LeftListBox.ItemsSource = myDataList;
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
myDataList = LoadListBoxData();
LeftListBox.ItemsSource = myDataList;
}
private ArrayList LoadListBoxData()
{
ArrayList itemsList = new ArrayList();
itemsList.Add("Item1");
itemsList.Add("Item2");
itemsList.Add("Item3");
itemsList.Add("Item4");
itemsList.Add("Item5");
itemsList.Add("Item6");
itemsList.Add("Item7");
itemsList.Add("Item8");
itemsList.Add("Item9");
itemsList.Add("Item10");
return itemsList;
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
// Find the right item and it's value and index
currentItemText = LeftListBox.SelectedValue.ToString();
currentItemIndex = LeftListBox.SelectedIndex;
RightListBox.Items.Add(currentItemText);
if (myDataList != null)
{
myDataList.RemoveAt(currentItemIndex);
}
// Refresh data binding
ApplyDataBinding();
}
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
// Find the right item and it's value and index
currentItemText = RightListBox.SelectedValue.ToString();
currentItemIndex = RightListBox.SelectedIndex;
// Add RightListBox item to the ArrayList
myDataList.Add(currentItemText);
// LeftListBox.Items.Add(RightListBox.SelectedItem);
RightListBox.Items.RemoveAt(RightListBox.Items.IndexOf(RightListBox.SelectedItem));
// Refresh data binding
ApplyDataBinding();
}
/// <summary>
/// Refreshes data binding
/// </summary>
private void ApplyDataBinding()
{
LeftListBox.ItemsSource = null;
// Bind ArrayList with the ListBox
LeftListBox.ItemsSource = myDataList;
}
just have a look at this
Move items from one listbox to another
http://www.c-sharpcorner.com/UploadFile/mahesh/WPFListBoxDataTransfer07272008130032PM/WPFListBoxDataTransfer.aspx
public partial class listtolist : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
for (int i = ListBox1.Items.Count - 1; i >= 0; i--)
{
if (ListBox1.Items[i].Selected)
{
ListBox2.Items.Add(ListBox1.Items[i]);
ListBox1.Items.Remove(ListBox1.Items[i]);
}
}
}
protected void Button2_Click(object sender, EventArgs e)
{
for (int i = ListBox2.Items.Count - 1; i >= 0; i--)
{
if (ListBox2.Items[i].Selected)
{
ListBox1.Items.Add(ListBox2.Items[i]);
ListBox2.Items.Remove(ListBox2.Items[i]);
}
}
}
}

Categories