UWP equivalent of Android's SpannableString with image inside - c#

Is there a way to implement an image within a TextBlock rather than outside of it? Android has a feature called SpaanableStringBuilder which allows the user to create text with different appearances. Does UWP have something similar?
MyTextBlock.Text = "Google" + ? + "icon";

As Raymond said, in UWP, RichTextBlock is needed for image and text mixing.
With Xaml
<RichTextBlock>
<Paragraph>
<Run Text="Something..."/>
<InlineUIContainer>
<Image Source="your_image_url" Width="20" Height="20"/>
</InlineUIContainer>
<Run Text="Something..."/>
</Paragraph>
</RichTextBlock>
With Code
var richTextBlock = new RichTextBlock();
var para = new Paragraph();
para.Inlines.Add(new Run() { Text = "Something..." });
var imgContainer = new InlineUIContainer();
var img = new Image();
img.Source = new BitmapImage(new Uri("your_image_url"));
imgContainer.Child = img;
para.Inlines.Add(imgContainer);
para.Inlines.Add(new Run() { Text = "Something..." });
richTextBlock.Blocks.Add(para);
Or you could write it this way, which more closely mirrors the XAML.
var richTextBlock = new RichTextBlock()
{
Blocks = {
new Paragraph {
Inlines = {
new Run { Text = "Something" },
new InlineUIContainer {
Child = new Image {
Source = new BitmapImage(new Uri("your_image_url"))
}
},
new Run { Text = "Something..."}
}
}
}
};

Related

Create from xaml DataGridTemplateColumn column in c#

I have short xaml code :
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}"></TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Category}" KeyUp="TextBox_KeyUp"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
But I dont know how to convert it on c#. I did that: but it dont work, and dont know how add Event to TextBox:
Edit: dont throw exception, but still dont work. Without event.
var a = new DataGridTemplateColumn() { Header = "Kategoria", Width = new DataGridLength(1, DataGridLengthUnitType.Star) };
var aa = new DataTemplate();
aa.Resources.Add(1, new TextBlock() { Text = new Binding("Category").ToString() });
a.CellTemplate = aa;
var aaa = new DataTemplate();
aaa.Resources.Add(2, new System.Windows.Controls.TextBox() { Text = new Binding("Category").ToString() });
a.CellEditingTemplate = aaa;
ProjectDataGrid.Columns.Add(a);
ProjectDataGrid.Columns.Add(new DataGridTextColumn() { Header = "Mnemonik", Binding = new Binding("Mnemoniese"), Width = new DataGridLength(1, DataGridLengthUnitType.Star) });
I think it might be helpful. I just convert your XAML markup in C# code step by step.
DataGridTemplateColumn templateColumn = new DataGridTemplateColumn
{
CellTemplate = new DataTemplate
{
DataType = typeof(TextBlock)
},
CellEditingTemplate = new DataTemplate
{
DataType = typeof(TextBox)
}
};
FrameworkElementFactory CategoryBlock = new FrameworkElementFactory(typeof(TextBlock));
CategoryBlock.SetBinding(TextBlock.TextProperty, new Binding("Category"));
templateColumn.CellTemplate.VisualTree = CategoryBlock;
FrameworkElementFactory CategoryTextBox = new FrameworkElementFactory(typeof(TextBox));
CategoryTextBox.SetBinding(TextBox.TextProperty, new Binding("Category"));
CategoryTextBox.AddHandler(KeyUpEvent, new KeyEventHandler(TextBox_KeyUp));
templateColumn.CellEditingTemplate.VisualTree = CategoryTextBox;
ProjectDataGrid.Columns.Add(templateColumn);

Can't get Click or Command to work on dynamically created MenuFlyOutItems

I have a TreeView with several layers in it. Each item is populated with an ObservableCollection of MenuFlyoutItem dependent on its object type created dynamically at runtime. It's important to note this is in a Windows 10 Universal App, so any solutions or recommendations need to be relevant to them.
The TreeView objects are created like so:
public TreeViewItemModel(object thing)
{
MenuItems.Clear();
if (thing.GetType() == typeof (Space))
{
var space = (Space)thing;
var parentName = string.Empty;
if (space.Parent != null)
{
parentName = space.Parent.Name;
}
Name = space.Name;
ParentName = parentName;
Id = space.Id;
var addDeviceMenuItem = new MenuFlyoutItem { Name = "AddDevice", Text = "Add Device"};
var addSensorMenuItem = new MenuFlyoutItem { Name = "AddSensor", Text = "Add Sensor" };
var addSpaceMenuItem = new MenuFlyoutItem { Name = "AddSpace", Text="Add Space"};
var updateMenuItem = new MenuFlyoutItem { Name = "UpdateSpaceInfo", Text = "Update Space Info" };
var deleteMenuItem = new MenuFlyoutItem { Name = "DeleteSpace", Text = "Delete Space" };
var items = new ObservableCollection<MenuFlyoutItem> {addDeviceMenuItem, addSensorMenuItem,addSpaceMenuItem, updateMenuItem, deleteMenuItem};
MenuItems = items;
Children = new ObservableCollection<TreeViewItemModel>(space.Children.Select(s => new TreeViewItemModel(s)).Union(space.Devices.Select(d => new TreeViewItemModel(d)).Union(space.Sensors.Select(sensor => new TreeViewItemModel(sensor)))));
}
else if (thing.GetType() == typeof (Device))
{
var device = (Device) thing;
var parentName = device.Space.Name;
Name = device.Name;
ParentName = parentName;
Id = device.Id;
var addMenuItem = new MenuFlyoutItem { Name = "AddSensor", Text = "Add Sensor" };
var updateMenuItem = new MenuFlyoutItem { Name = "UpdateDeviceInfo", Text = "Update Device Info" };
var deleteMenuItem = new MenuFlyoutItem { Name = "DeleteDevice", Text = "Delete Device" };
var items = new ObservableCollection<MenuFlyoutItem> { addMenuItem, updateMenuItem, deleteMenuItem };
MenuItems = items;
Children = new ObservableCollection<TreeViewItemModel>(device.Sensors.Select(s => new TreeViewItemModel(s)));
}
else if (thing.GetType() == typeof(Sensor))
{
var sensor = (Sensor) thing;
var space = sensor.Space.Name ?? string.Empty;
var device = sensor.Device;
ParentName = device == null ? "No Matching Device" : device.Name;
Name = sensor.Id.ToString();
Id = sensor.Id;
ParentName = space;
var updateMenuItem = new MenuFlyoutItem { Name = "UpdateSensorInfo", Text = "Update Sensor Info" };
var deleteMenuItem = new MenuFlyoutItem { Name = "DeleteSensor", Text = "Delete Sensor" };
var items = new ObservableCollection<MenuFlyoutItem> {updateMenuItem, deleteMenuItem};
MenuItems = items;
Children = null;
}
}
My TreeView in xaml looks like this:
<controls:TreeView x:Name="TreeViewList" Grid.Row="0" Margin="5" ItemsSource="{Binding TreeSpaces}">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<data:DataTemplateExtensions.Hierarchy>
<data:HierarchicalDataTemplate ItemsSource="{Binding Children}"/>
</data:DataTemplateExtensions.Hierarchy>
<Button x:Name="TreeButton" Content="{Binding Name}" BorderThickness="0" BorderBrush="Transparent" Background="Transparent">
<Button.Flyout>
<Flyout common:BindableFlyout.ItemsSource="{Binding MenuItems}">
<common:BindableFlyout.ItemTemplate>
<DataTemplate>
<MenuFlyoutItem Text="{Binding Text}"/>
</DataTemplate>
</common:BindableFlyout.ItemTemplate>
</Flyout>
</Button.Flyout>
</Button>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
I can't seem to get any form of event handling to trigger on the MenuFlyoutItem to work.
Initially I tried <MenuFlyoutItem Name={Binding Name} Text={Binding Text} view:EventHandlers.Attach="Click"/> This works off a custom MVVM implementation to attach events to ViewModel handlers. Behind the scenes, our attaching mechanism takes the Name of the object and associates with a Click so it would look like this in the View Model if the name were say SaveButton: public void SaveButton_Click(object sender, RoutedEventArgs e). Now, I've normally never had an issue with this, but I thought the problem might have stemmed from trying to use DataBinding for the MenuFlyoutItem's Name rather than the traditional x:Name="blah blah"; however, trying that did not work either. I thought maybe this could be because it was a MenuFlyoutItem rather than a button per say, so I tried changing it to a <Button/> with all the respective stuff, and that didn't work either. So, I went back to MenuFlyoutItem and tried to use the Command property instead. i.e. Command="{Binding MenuItemSelected}". Then in my ViewModel I have the following:
public RelayCommand<object> MenuItemSelected { get; internal set; }
public TreeViewPageVM()
{
MenuItemSelected = new RelayCommand<object>(TestAction);
}
private void TestAction(object sender)
{
}
That didn't work either... So, as much as I want to use MVVM, I resulted to trying code behind by using the traditional <MenuFlyoutItem x:Name="MenuItem" Text="{Binding Text} Click="MenuItem_Clicked" and a corresponding private void MenuItem_Clicked(object sender, RoutedEventArgs e) handler. Much to my surprise this didn't work either. So, I'm not sure what's causing what seems like a suppression on my MenuFlyoutItem's ability to generate events, but some help on this would be appreciated.
Ideally whether it's a click event or command event, I'd like to handle it in my ViewModel, and I'd want the command or click event to be able to grab the Content on the button that generated the Flyout Menu (I'll need that during post processing of the event) as well as the Text from the MenuFlyoutItem that was clicked.
Just in case there needs to be any additional clarity:
I would have objects in the tree like so
----Object1
--------SubObject
and if I click on SubObject (which in this case is a Button that has a flyout attached) a flyout menu with options like: Add, Update, Delete show up. When I click/tap on Add for example, I need my end event handler or command to be aware of SubObject (specifically it's Content because it's a button) and the MenuFlyoutItem that was clicked (specifically the Text property so I know whether I need to add, update, or delete).
The quick and correct answer given above (i.e.adding the Command in the same code where you create the MenuFlyoutItem) leads to the fact that your code violates the MVVM pattern, because you create View's Controls in the ViewModel, so a better solution would be
1) implementing a ViewModel for the Flyout
public class DeviceViewModel
{
public string Name { get; set; }
internal int treeNum;
private DelegateCommand flyoutCommand;
public ICommand FlyoutCommand
{
get
{
if (flyoutCommand == null)
{
flyoutCommand = new DelegateCommand((parameter) => FlyoutLogic(), (parameter) => CanFlyout());
}
return flyoutCommand;
}
}
private bool CanFlyout()
{
return true;
}
private void FlyoutLogic()
{
Debug.WriteLine("here we go " + Name + treeNum);
}
}
2) instantiating the ViewModel
var addDeviceMenuItem = new DeviceViewModel { Name = "AddDevice", treeNum = _itemId };
var addSensorMenuItem = new DeviceViewModel { Name = "AddSensor", treeNum = _itemId };
var addSpaceMenuItem = new DeviceViewModel { Name = "AddSpace", treeNum = _itemId };
var updateMenuItem = new DeviceViewModel { Name = "UpdateSpaceInfo", treeNum = _itemId };
var deleteMenuItem = new DeviceViewModel { Name = "DeleteSpace", treeNum = _itemId };
var items = new ObservableCollection<DeviceViewModel> { addDeviceMenuItem, addSensorMenuItem, addSpaceMenuItem, updateMenuItem, deleteMenuItem };
tree.Add(
new TreeItemModel
{
Branch = b,
Depth = d,
Text = "Item " + _itemId++,
Children = BuildTree(d, b),
MenuItems = items
});
with
ObservableCollection<DeviceViewModel> _menuItems;
public ObservableCollection<DeviceViewModel> MenuItems
{
get { return _menuItems; }
set { this.SetProperty(ref _menuItems, value); }
}
3) and finally binding the XAML to the ViewModel
<controls:TreeView x:Name="TreeViewList" Grid.Row="0" Margin="5" ItemsSource="{Binding TreeItems}">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<data:DataTemplateExtensions.Hierarchy>
<data:HierarchicalDataTemplate ItemsSource="{Binding Children}"/>
</data:DataTemplateExtensions.Hierarchy>
<Button
x:Name="TreeButton" Content="{Binding Text}" BorderThickness="3" Background="Transparent">
<Button.Flyout>
<Flyout common:BindableFlyout.ItemsSource="{Binding MenuItems}">
<common:BindableFlyout.ItemTemplate>
<DataTemplate>
<MenuFlyoutItem Text="{Binding Name}" Command="{Binding FlyoutCommand}"/>
</DataTemplate>
</common:BindableFlyout.ItemTemplate>
</Flyout>
</Button.Flyout>
</Button>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
You can add the Command in the same code where you create the MenuFlyoutItem, so
var addDeviceMenuItem = new MenuFlyoutItem { Name = "AddDevice", Text = "Add Device"
};
addDeviceMenuItem.Command = AddDeviceCommand;

How can i display chart from code behind in windows phone

I create a chart in my windows phone app.this is my code XAML
<amq:SerialChart x:Name="line" DataSource="{Binding results}" CategoryValueMemberPath="month"
AxisForeground="White"
PlotAreaBackground="Black"
GridStroke="DarkGray" >
<amq:SerialChart.Graphs>
<amq:LineGraph Title="Sales" ValueMemberPath="actual" Brush="red" StrokeThickness="5" />
</amq:SerialChart.Graphs>
</amq:SerialChart>
How can i write this XAML with c# (code behind only)
How can i write this XAML with c# (code behind only)
In general this is usually not a good idea. But if you must, you would use something along these lines:
var chart = new SerialChart
{
CategoryValueMemberPath = "month",
AxisForeground = new SolidColorBrush(Colors.White),
PlotAreaBackground = new SolidColorBrush(Colors.Black),
GridStroke = new SolidColorBrush(Colors.DarkGray)
};
chart.SetBinding(SerialChart.DataSourceProperty, new Binding("results"));
var lineGraph = new LineGraph
{
Title = "Sales",
ValueMemberPath = "actual",
Brush = new SolidColorBrush(Colors.Red),
StrokeThickness = "5"
};
chart.Graphs.Add(lineGraph);
Then you would just need to add the chart to the page/container using for example stackPanel.Children.Add(chart).
var chart = new SerialChart
{
CategoryValueMemberPath = "month",
AxisForeground = new SolidColorBrush(Colors.White),
PlotAreaBackground = new SolidColorBrush(Colors.Black),
GridStroke = new SolidColorBrush(Colors.DarkGray)
};
chart.SetValue(SerialChart.DataSourceProperty, new Binding("results"));
var lineGraph = new LineGraph
{
Title = "Sales",
ValueMemberPath = "actual",
Brush = new SolidColorBrush(Colors.Red),
StrokeThickness = 5
};
chart.Graphs.Add(lineGraph);

Add images to ListBox (c#, windows phone 7)

I am developing the Windows Phone 7, I need to add images to ListBox.
I want do it with C# code, not XAML.
I read about it, but everyone uses BitmapImage, which I can't get to work on Windows Phone 7.
I have XAML code:
<StackPanel Margin="0,0,0,17">
<local:MatchDates Adress="http://soccernet.espn.go.com/results/_/league/esp.1/spanish-la-liga?cc=57393" />
</StackPanel>
and C# function in my class MatchDates:
void add_items(List<List<string>> code)
{
if (code.Count == 0)
this.Items.Add("no mathes");
else
{
foreach (List<string> temp1 in code)
{
foreach (string temp2 in temp1)
{
this.Items.Add(temp2);
}
this.Items.Add("---------------------------------");
}
}
}
How can I add images in function add_items?
This code:
Uri uri = new Uri("/eng.png", UriKind.Relative);
BitmapImage bitmap = new BitmapImage(uri);
Image img = new Image();
img.Height = 30;
img.Width = 30;
img.Source = bitmap;
this.Items.Add(img);
this.Items.Add(temp2);
Only empty space is presented, How do I add images to ListBox?
One of the ways I used:
XAML:
<ListBox Name="lstView" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImagePath}"></Image>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C#:
public class Article
{
public string Name { get; set; }
public string ImagePath { get; set; }
}
Article article1 = new Article() { Name = "name1", ImagePath = "path of image 1" };
Article article2 = new Article() { Name = "name2", ImagePath = "path of image 2" };
var articles = new List<Article>();
articles.Add(article1);
articles.Add(article2);
lstView.DataContext = articles;
For retrieving articles I use WCF service.
BitmapImage is supported. You have to declare the BitmapImage as ImageSource.

How can I add multiple FlowDocumentReaders to a StackPanel?

Thanks to Leom's answer I was able to add a FlowDocument to a StackPanel by wrapping it in a FlowDocumentReader.
But now I have two problems:
it seems only the first FlowDocumentReader is added and the rest ignored
there is an unwanted margin that I can't get rid of
How can I add multiple FlowDocumentReaders to a StackPanel without the unwanted margin?
alt text http://www.deviantsart.com/upload/1ndiqqe.png
XAML:
<Window x:Class="TestFlowdoc23432.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="200" Width="300">
<StackPanel Margin="10">
<ContentControl x:Name="MainArea"/>
</StackPanel>
</Window>
Code Behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace TestFlowdoc23432
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
StackPanel sp = new StackPanel();
TextBlock tb1 = new TextBlock();
tb1.Text = "first text block";
sp.Children.Add(tb1);
TextBlock tb2 = new TextBlock();
tb2.Text = "second text block";
sp.Children.Add(tb2);
sp.Children.Add(GetFlowDocumentReader("first flow document reader"));
sp.Children.Add(GetFlowDocumentReader("second flow document reader"));
MainArea.Content = sp;
}
FlowDocumentReader GetFlowDocumentReader(string text)
{
FlowDocumentReader fdr = new FlowDocumentReader();
FlowDocument fd = new FlowDocument();
fdr.Document = fd;
fdr.Margin = new Thickness(0);
Paragraph par = new Paragraph();
par.Margin = new Thickness(0);
fd.Blocks.Add(par);
Run r = new Run(text);
par.Inlines.Add(r);
return fdr;
}
}
}
To make the text appear to the left you need to set the pagepadding property on your flowdocument as follows:
fd.PagePadding = new Thickness(0);
the reason that you only seem to get the first reader is becuase it fills the space available (move it to be the first object and you will not see the textblocks).
If you change the FlowDocumentReader to be a FlowDocumentScrollViewer and use the VerticalScrollBarVisibility property then you can get the desired effect. The following is your GetFlowDocumentReader method with the changes applied:
FlowDocumentScrollViewer GetFlowDocumentReader(string text)
{
FlowDocumentScrollViewer fdr = new FlowDocumentScrollViewer();
FlowDocument fd = new FlowDocument();
fdr.Document = fd;
fdr.Margin = new Thickness(0);
Paragraph par = new Paragraph();
par.Margin = new Thickness(0);
fd.Blocks.Add(par);
Run r = new Run(text);
par.Inlines.Add(r);
fd.PagePadding = new Thickness(0);
fdr.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
return fdr;
}

Categories