I have a program which works like a simple power point program. I am not working in a MVVM pattern.
I am saving all the slides that a user has created to an XML file and then reading this back in at a later date. My ListView which stores a preview of all slides currently created in the program when loaded only loads the ListView.Items.Content for the last slide in the list.
The following is the code I use to read the XML file.
private void Load()
{
List<SlideItems> listProjectContents = DeSerializeObjects();
if (listProjectContents != null)
{
int loadCount = 0;
foreach (SlideItems slide in listProjectContents)
{
CreateNewSlide();
ListViewItem i = (ListViewItem)slideListView.Items[loadCount++];
BitmapSource bSource = Base64ToImage(slide.slidePreview);
Image img = new Image();
img.Source = bSource;
img.Height = 90;
img.Width = 190;
Border b = new Border();
StackPanel s = new StackPanel();
TextBlock t = new TextBlock();
t.Inlines.Add(loadCount.ToString());
s.Children.Add(t);
s.Children.Add(img);
b.Child = s;
i.Content = b;
}
}
}
Can anyone see from this why only the ListView.Items.Content of the last ListView Item is displayed when I load from an XML file??
This code is awful. Instead of trying to fix it, you should try to understand how things are done in wpf. Even if for some reason you are not using MVVM you can (and should) use data binding. In your case, you should
1) define a data template:
<ListView x:Name="slideListView">
<ListView.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel>
<TextBlock Text="{Binding Text}"/>
<Image Width="190" Height="90" Source="{Binding Image}"/>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
2) define item
class MyItem
{
public BitmapSource Image { get; set; }
public string Text { get; set; }
}
3) populate your ListView (should be done using MVVM instead, but oh well)
private void Load()
{
slideListView.Items.Clear();
List<SlideItems> listProjectContents = DeSerializeObjects();
if (listProjectContents != null)
{
int loadCount = 0;
foreach (SlideItems slide in listProjectContents)
{
BitmapSource bSource = Base64ToImage(slide.slidePreview);
var item = new MyItem { Text = (loadCount++).ToString(), Image = bSource };
slideListView.Items.Add(item);
}
}
}
Related
I'm trying to create a Nonogram (aka PuzzleCross) puzzle grid in C#/WPF, and have created two UserControls to contain the row and column keys. Each UserControl consists of a Border containing a TextBlock, with a DependencyProperty named TextControl to make the Text property accessible outside of the UserControl. Everything works fine except that the text isn't actually displayed when run. The TextControl contains the correct text, as tested with a MouseDown event and a MessageBox, but for some reason the text just isn't there.
Can anyone help me figure out what I'm missing? I have a feeling it's a simple thing, but I'm just not seeing it.
Horizontal UserControl:
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" Height="10" Width="100">
<TextBlock Text="{Binding ElementName=HorizontalRowLabel, Path=TextContent}" Foreground="Black" FontSize="6" MouseDown="TextBlock_MouseDown"/>
</Border>
Horizontal C#:
public partial class HorizontalRowLabel : UserControl
{
public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string),
typeof(HorizontalRowLabel), new FrameworkPropertyMetadata(""));
public string TextContent
{
get { return (string)GetValue(TextContentProperty); }
set { SetValue(TextContentProperty, value); }
}
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show(TextContent);
}
public HorizontalRowLabel()
{
InitializeComponent();
}
}
//Adds text HorizontalRowLabel UserControl, then adds HRL to Grid.
public void InitRowKeys(Grid puzzle)
{
for(int i = 0; i < HorizontalKeys.Length; i++)
{
RowDefinition row = new RowDefinition();
HorizontalRowLabel hrow = new HorizontalRowLabel();
row.Height = new GridLength(10);
for(int j = 0; j < HorizontalKeys[i].Length; j++)
{
if(HorizontalKeys[i].Length == 0 || j == HorizontalKeys[i].Length - 1)
{
hrow.TextContent += HorizontalKeys[i][j].ToString();
hrow.Foreground = Brushes.Black;
hrow.SetValue(Grid.RowProperty, i);
hrow.SetValue(Grid.ColumnProperty, 0);
hrow.FontSize = 6;
hrow.HorizontalAlignment = HorizontalAlignment.Right;
hrow.VerticalAlignment = VerticalAlignment.Center;
}
else
{
hrow.TextContent += HorizontalKeys[i][j].ToString() + " ";
hrow.SetValue(Grid.RowProperty, i);
hrow.SetValue(Grid.ColumnProperty, 0);
hrow.FontSize = 6;
hrow.HorizontalAlignment = HorizontalAlignment.Right;
hrow.VerticalAlignment = VerticalAlignment.Center;
}
}
//puzzle.Margin = new Thickness(0,50,0,0);
hrow.Width = 100;
hrow.Height = 30;
puzzle.RowDefinitions.Add(row);
puzzle.Children.Add(hrow);
}
}
A Binding like
Text="{Binding ElementName=HorizontalRowLabel, Path=TextContent}"
only works if you have assigned the x:Name attribute to the UserControl:
<UserControl ... x:Name="HorizontalRowLabel">
...
</UserControl>
That is however not necessary with a RelativeSource Binding:
Text="{Binding TextContent, RelativeSource={RelativeSource AncestorType=UserControl}}"
I am developing WPF application. In which I am adding CheckBoxes to a ListBox in following way.
foreach (User ls in lst)
{
AddContacts(ls, lstContactList);
}
private void AddContacts(User UserData, ListBox lstbox)
{
try
{
var txtMsgConversation = new CheckBox()
{
Padding = new Thickness(1),
IsEnabled = true,
//IsReadOnly = true,
Background = Brushes.Transparent,
Foreground = Brushes.White,
Width = 180,
Height = 30,
VerticalAlignment = VerticalAlignment.Top,
VerticalContentAlignment = VerticalAlignment.Top,
Content = UserData.Name, //+ "\n" + UserData.ContactNo,
Margin = new Thickness(10, 10, 10, 10)
};
var SpConversation = new StackPanel() { Orientation = Orientation.Horizontal };
SpConversation.Children.Add(txtMsgConversation);
var item = new ListBoxItem()
{
Content = SpConversation,
Uid = UserData.Id.ToString(CultureInfo.InvariantCulture),
Background = Brushes.Black,
Foreground = Brushes.White,
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Gray
};
item.Tag = UserData;
lstbox.Items.Add(item);
}
catch (Exception ex)
{
//Need to log Exception
}
}
Now I need to get the checked items from ListBox. How do I proceed here, I tried below code, which returning null,
CheckBox chkBox = lstContactList.SelectedItem as CheckBox;
Thoughts?
The way of creating dynamic multiple items in a listbox is not in codebehind, but to create a template for the items, and then bind it to a list of items.
Example
Say I have a bunch of passages List<Passage> Passages { get; set; }:
public class Passage
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
In my xaml I create a template and bind to it
<ListBox ItemsSource="{Binding Passages}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" />
<TextBlock Text="{Binding Path=Name, StringFormat=Passage: {0}}"
Foreground="Blue" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The result looks like this for my four passages "Alpha", "Beta", "Gamma" and "I-25":
Then if I want the selected item, such as the recently checked Beta above, I just enumerate my List for the selected one(s).
var selecteds = Passages.Where(ps => ps.IsSelected == true);
Need to list different types objects in one ListBox? Say from binding to a composite collection or an ObservableCollection<T>?
See my answers here:
Composite Collection
ObservableCollection
I have a problem displaying custom UserControls in my ListBox programmatically. I just can't seem to figure out what is wrong. The list-item shows up without image or text.
My project consists of:
MainWindow.xaml
MainWindow.xaml.cs
cvMenuItem.xaml
cvMenuItem.xaml.cs
Code of MainWindow.xaml.cs
private void cvMenuItem_MouseLeftButtonUp_1(object sender, MouseButtonEventArgs e)
{
lstContacts.Items.Clear();
cvMenuItem test = new cvMenuItem("test",
Environment.GetEnvironmentVariable("USERPROFILE") + #"\Downloads\images.jpg");
lstContacts.Items.Add(test);
}
Code of cvMenuItem.xaml.cs
public partial class cvMenuItem : UserControl
{
public cvMenuItem()
{
InitializeComponent();
}
public cvMenuItem(string text, string Logo)
{
this.Height = 50;
this.Width = 186;
txtService = new TextBlock() { Width = 100, Height = 50 };
imgLogo = new Image() { Width = 50, Height = 50 };
//Just found out, adding the objects as childeren partially works
this.AddChild(imgLogo);
//But I can't add txtService as Childeren
//this.AddChild(txtService);
this.Services = text;
this.Logo = Logo;
}
public string Services
{
get{ return txtService.Text.ToString() }
set
{
txtService.Text = value;
}
}
public string Logo
{
get{ return imgLogo.Source.ToString(); }
set
{
var uriSource = new Uri(value);
imgLogo.Source = new BitmapImage(uriSource);
}
}
My cvMenuItem.xaml.cs
<UserControl x:Class="WpfApplication1.cvMenuItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="50" Width="186">
<Grid Width="186" VerticalAlignment="Top">
<Image Name="imgLogo" Height="50" Width="50" HorizontalAlignment="Left" VerticalAlignment="Top" OpacityMask="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}" />
<TextBlock Name="txtService" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Bottom" Height="18" Width="121" Margin="70,0,0,18" RenderTransformOrigin="0.499,1.932"/>
</Grid>
</UserControl>
First of all you need to call InitializeComponent in the custom constructor you have added, as that is needed to process the XAML properly. Otherwise all the controls you add in the XAML will be null when running the application.
Additionally it makes no sense to create the TextBlock and Image again in the code-behind. You just have to use the ones created in the XAML.
So to get it working, change the code in the constructor to the following:
public cvMenuItem(string text, string Logo)
{
InitializeComponent();
this.Height = 50;
this.Width = 186;
this.Services = text;
this.Logo = Logo;
}
I need to show multiple buttons, but each one must have a different background than other buttons, I have been working on it, but I only got to display multiple buttons but with the same background.
Here is the XAML:
<Window x:Class="apple.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="370" Width="525">
<Grid>
<Image Source="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg" Stretch="Fill"/>
<DockPanel Name="dock">
<UniformGrid Name="gridx" DockPanel.Dock="Top" Rows="3" Columns="3" Height="334">
</UniformGrid>
</DockPanel>
</Grid>
</Window>
Also, here is the C# code:
namespace apple
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
masterGUI();
}
public void masterGUI()
{
ImageBrush ib = new ImageBrush();
IconImage[] ico = null;
Bitmap[] img = null;
string[] list = null;
string[] link = Directory.GetFiles(#"C:\ProgramData\Microsoft\Windows\Start Menu\Programs", "*.lnk", SearchOption.AllDirectories);
list = new string[link.Length];
ico = new Icon[link.Length];
img = new Bitmap[link.Length];
for (int n = 0; n < link.Length; n++)
{
System.Windows.Controls.Button newBtn = new Button();
list[n] = System.IO.Path.GetFileNameWithoutExtension(link[n]);
FileToImageIconConverter some = new FileToImageIconConverter(link[n]);
ImageSource imgSource = some.Icon;
ib.ImageSource = imgSource;
newBtn.Background = ib;
newBtn.Content = list[n];
gridx.Children.Add(newBtn);
}
}
}
}
Any idea? thank you.
The ImageBrush needs to be created in the for-loop individually for each item. Otherwise you will end up with the same background for every item.
Also you are approaching this the "wrong" way, in WPF you should use data binding and data templating for this sort of thing instead of imperative looping.
i need to show a list of item in a ListBox from the bottom in WP7.
So in case i have some items that the height sum of them is < of ListBox Height i need to have a blank item at the top with the difference of the Height.
I have to do this because i set the ItemSource of Listbox, so i cannot know what is the right height of all items before load them.
In Item_loaded event of every Item i save the height and at the last i need to set the Height of the First.
<ListBox x:Name="ConvListBox" Margin="0,0,-12,0" >
<ListBox.ItemTemplate >
<DataTemplate >
<Grid>
<StackPanel Name="BaloonMessage" Margin="3,0,0,0" Loaded="Baloon_Loaded" Tag="{Binding IsSentMsg}" >
<TextBlock Name="SMSText" Text="{Binding SMSText}" Margin="7,3,8,35" TextWrapping="Wrap" Height="Auto" Width="Auto" FontSize="22" Foreground="White"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I set the ItemsSource and add a blank item at top, and a blank at bottom:
ObservableCollection<ClassMessaggio> messaggi =
new ConversazioneViewModel(MessaggioConversazione).Conversazione;
ClassMessaggio FirstLineScrollMessage = new ClassMessaggio();
FirstLineScrollMessage.IsSentMsg = "3";
messaggi.Insert(0, FirstLineScrollMessage);
ClassMessaggio LastLineScrollMessage = new ClassMessaggio();
LastLineScrollMessage.IsSentMsg = "2";
messaggi.Insert(messaggi.Count, LastLineScrollMessage);
this.ConvListBox.ItemsSource = messaggi;
And at Item_Loaded i'm trying this:
var Panel = (StackPanel) sender;
if (Panel != null)
{
Grid grid = (Grid)Panel.Parent;
Border baloon = (Border)Panel.FindName("Baloon");
baloon.Width = grid.Width - 100;
if (Panel.Tag.ToString() == "3")
{
TotalBaloonsHeight = 0;
baloon.Background = grid.Background;
baloon.Name = "FirstScrollBaloon";
}
else if (Panel.Tag.ToString() == "2")
{
baloon.Height = 2;
Panel.Height = 2;
grid.Height = 2;
Border FirstBaloon = (Border)ConvListBox.FindName("FirstScrollBaloon");
if (FirstBaloon != null)
{
FirstBaloon.Height = ConvListBox.Height - TotalBaloonsHeight;
}
}
else
{
TotalBaloonsHeight = TotalBaloonsHeight + baloon.Height;
}
}
My problem is that this line return me always null :(
Border FirstBaloon = (Border)ConvListBox.FindName("FirstScrollBaloon");
I hope is clear, sorry for my english.
EDIT::
Ok this should work:
var Baloons = LayoutRoot.GetVisualDescendants().OfType<Border>();
foreach (var FirstBaloon in Baloons)
{
if (FirstBaloon != null)
{
if (FirstBaloon.Name == "FirstScrollBaloon")
{
FirstBaloon.Height = ConvListBox.ActualHeight - TotalBaloonsHeight;
break;
}
}
}
You can get to the first ListBoxItem using this code:
ListBoxItem item0 = ConvListBox.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
From there you can modify it's Height, etc.
Thanks,
Stefan Wick - Microsoft Silverlight