I'm trying to create a xamDataChart with StackedColumnSeries. In my use case I need to be able to create variable number of StackedColumnSeries and StackedFragmentSeries so I'm creating everything in code behind. StackedColumnSeries ItemsSource is set to a list of dictionaries. Everything works fine if dictionaries have decimal values. But I need them to have object values and fetch the final value from that object. And I can't get it right, the chart just shows empty so the ValueMemberPath must not be working correctly.
Here's an example code demonstrating the problem:
var window = new Window() { Width = 600, Height = 400, WindowStartupLocation = WindowStartupLocation.CenterScreen };
var chart = new XamDataChart();
Axis xAxis = new CategoryXAxis() { ItemsSource = new List<string> { "First", "Second" } };
Axis yAxis = new NumericYAxis() { MinimumValue = 0, MaximumValue = 1000 };
chart.Axes.Add(xAxis);
chart.Axes.Add(yAxis);
// Trying to fetch chart fragment values from value member's property: Does not work.
var testItems = new List<Dictionary<string, TestPoint>>();
var stackedSeries = new StackedColumnSeries() { ItemsSource = testItems, XAxis = xAxis as CategoryXAxis, YAxis = yAxis as NumericYAxis };
stackedSeries.Series.Add(new StackedFragmentSeries() { ValueMemberPath = "[Serie1].PointValue" });
stackedSeries.Series.Add(new StackedFragmentSeries() { ValueMemberPath = "[Serie2].PointValue" });
testItems.Add(new Dictionary<string, TestPoint>() { { "Serie1", new TestPoint(100) }, { "Serie2", new TestPoint(200) } });
testItems.Add(new Dictionary<string, TestPoint>() { { "Serie1", new TestPoint(300) }, { "Serie2", new TestPoint(400) } });
// Value member is decimal and using it directly, works fine.
//var testItems = new List<Dictionary<string, decimal>>();
//var stackedSeries = new StackedColumnSeries() { ItemsSource = testItems, XAxis = xAxis as CategoryXAxis, YAxis = yAxis as NumericYAxis };
//stackedSeries.Series.Add(new StackedFragmentSeries() { ValueMemberPath = "[Serie1]" });
//stackedSeries.Series.Add(new StackedFragmentSeries() { ValueMemberPath = "[Serie2]" });
//testItems.Add(new Dictionary<string, decimal>() { { "Serie1", 100 }, { "Serie2", 200 } });
//testItems.Add(new Dictionary<string, decimal>() { { "Serie1", 300 }, { "Serie2", 400 } });
chart.Series.Add(stackedSeries);
window.Content = chart;
window.ShowDialog();
The TestPoint class used in above example:
class TestPoint
{
public decimal PointValue { get; set; }
public TestPoint (decimal value)
{
PointValue = value;
}
}
I'm using Infragistics version 14.2 (the problem did not occur on Infragistics 13.1).
I got it working by changing ValueMemberPath from ValueMemberPath = "[Serie1].PointValue" to ValueMemberPath = "[Serie1][PointValue]".
Related
I am not very experienced with Windows Forms and am not pretty sure how I should tackle with this task the best way possible. I have a class which looks like this:
public class VariableMapping
{
private string variableName;
private string variableText;
private string variableSelector;
public VariableMapping(string variableName, string variableText, string variableSelector)
{
this.VariableName = variableName;
this.VariableText = variableText;
this.VariableSelector = variableSelector;
}
public string VariableName
{
get { return this.variableName; }
set { this.variableName = value; }
}
public string VariableText
{
get { return this.variableText; }
set { this.variableText = value; }
}
public string VariableSelector
{
get { return this.variableSelector; }
set { this.variableSelector = value; }
}
}
I want to create a DataGridView which should be bound to a number of elements of type VariableMapping in a list. However, I want only 1 of the properties(VariableText) of every instance to be shown in the DataGridView but I want to be able to address the whole object through the DataGrid when I need to. I also need to add 2 more custom columns: a ComboBox with predefined values and a NumberBox.
It might seem a really simple task but I'm trully unexperienced in WinForms and couldn't find a solution I can use already. Thank you!
Edit: I am trying something like this but it doesn't seem to work properly:
public partial class MappingTable : Form
{
private DataGridView dataGridView1 = new DataGridView();
public MappingTable(List<VariableMapping> variableMappings)
{
InitializeComponent();
var colors = new List<string>() { "#color_k1", "#color_k2", "#color_s1" };
dataGridView1.AutoGenerateColumns = false;
dataGridView1.AutoSize = true;
dataGridView1.DataSource = variableMappings;
DataGridViewColumn titleColumn = new DataGridViewColumn();
titleColumn.DataPropertyName = "VariableText";
titleColumn.HeaderText = "Variable";
titleColumn.Name = "Variable*";
dataGridView1.Columns.Add(titleColumn);
DataGridViewComboBoxColumn colorsColumn = new DataGridViewComboBoxColumn();
colorsColumn.DataSource = colors;
colorsColumn.HeaderText = "Color";
dataGridView1.Columns.Add(colorsColumn);
DataGridViewTextBoxColumn opacityColumn = new DataGridViewTextBoxColumn();
opacityColumn.HeaderText = "Opacity";
dataGridView1.Columns.Add(opacityColumn);
this.Controls.Add(dataGridView1);
this.AutoSize = true;
}
}
I'm trying to add an ImageComboBoxEdit control onto a UserControl within my WinForms application.
public ShortCutUserControl()
{
var imageCollection = new ImageCollection { ImageSize = new Size(48, 48) };
imageCollection.Images.Add(Image.FromFile(#"Keyboard\ctrl.ico"));
imageCollection.Images.Add(Image.FromFile(#"Keyboard\alt.ico"));
functionKeyImageComboBoxEdit.Properties.LargeImages = imageCollection;
ImageComboBoxItem ctrlItem = new ImageComboBoxItem
{
Description = "Ctrl",
ImageIndex = 0
};
ImageComboBoxItem altItem = new ImageComboBoxItem
{
Description = "Alt",
ImageIndex = 1
};
functionKeyImageComboBoxEdit.Properties.Items.Add(altItem);
functionKeyImageComboBoxEdit.Properties.Items.Add(ctrlItem);
}
When the control is loaded:
I can't change the currently either directly through code or in the UI.
functionKeyImageComboBoxEdit.SelectedIndex = 0;
I've tried attaching events to the functionKeyImageComboBoxEdit, but none of these seem to be fired/captured;
functionKeyImageComboBoxEdit.SelectedIndexChanged += FunctionKeyImageComboBoxEditOnSelectedIndexChanged;
private void FunctionKeyImageComboBoxEditOnSelectedIndexChanged(object sender, EventArgs eventArgs)
{
//throw new NotImplementedException();
}
What am I missing from my code? I've been looking at the DevExpress ImageComboBoxEdit Documentation but can't see any problem.
The cause of the issue is that you don't set values for ImageComboBoxItems. Do this like:
ImageComboBoxItem ctrlItem = new ImageComboBoxItem
{
Description = "Ctrl",
ImageIndex = 0,
Value = "Ctrl"
};
ImageComboBoxItem altItem = new ImageComboBoxItem
{
Description = "Alt",
ImageIndex = 1,
Value = "Alt"
};
I use a ToolStripControlHost to wrap a ListBox control for adding it into a ToolStripDropDown, but found items I assign to ListBox.DataSource not shown up, and ComboBox.DataSource not work as well, I don't understand why ListContorl.DataSource not function in ToolStripControlHost.
ListBox listBox = new ListBox();
listBox.DataSource = new string[] { "1", "2", "3" };
ToolStripControlHost host = new ToolStripControlHost(listBox)
{
Margin = Padding.Empty,
Padding = Padding.Empty,
AutoSize = false
};
ToolStripDropDown dropDown = new ToolStripDropDown() { AutoClose = false };
dropDown.Items.Add(host);
dropDown.Show();
Edit
I found the problem is ToolStripDropDown has not parents to provide BindingContext, so it will happen to any control with DataManager.
Good question. Seems like the ListBox has to be added to a top level control (such as a Form) in order to force it to use the DataSource property. E.g. Add this code after the DataSource is assigned:
public class DataForm : Form {
ToolStripDropDown dropDown = new ToolStripDropDown() { AutoClose = true };
ListBox listBox = new ListBox();
public DataForm() {
listBox.DataSource = new string[] { "1", "2", "3" };
var hWnd = listBox.Handle; // required to force handle creation
using (var f = new Form()) {
f.Controls.Add(listBox);
f.Controls.Remove(listBox);
}
ToolStripControlHost host = new ToolStripControlHost(listBox) {
Margin = Padding.Empty,
Padding = Padding.Empty,
AutoSize = false
};
dropDown.Items.Add(host);
}
protected override void OnMouseClick(MouseEventArgs e) {
base.OnMouseClick(e);
dropDown.Show(Cursor.Position);
}
}
You could also look at the ListBox.cs source code to try and figure out underlying cause: http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/ListBox.cs,03c7f20ed985c1fc
I found the problem is ToolStripDropDown has no parents to provide a BindingContext, so the solution is assign the BindingContext of the Form.
ListBox listBox = new ListBox();
listBox.DataSource = new string[] { "1", "2", "3" };
listBox.BindingContext = this.BindingContext; //assign a BindingContext
ToolStripControlHost host = new ToolStripControlHost(listBox)
{
Margin = Padding.Empty,
Padding = Padding.Empty,
AutoSize = false
};
ToolStripDropDown dropDown = new ToolStripDropDown() { AutoClose = false };
dropDown.Items.Add(host);
dropDown.Show();
I'd like to know the orientation of the device (Android, iOS & Windows Phone) at the time I'm building up my page. The page is having a grid with 3 columndefinitions and should have 5 columndefinitions as soon as the orientation got changed to landscape.
Grid grid = new Grid
{
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
RowSpacing = 15,
ColumnSpacing = 15,
Padding = new Thickness(15),
ColumnDefinitions =
{
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }
}
};
for (int i = 0; i < 12; i++)
{
Image img = new Image()
{
Source = "ButtonBlue.png"
};
//if(DependencyService.Get<IDeviceInfo>().IsPortraitOriented())
//{
grid.Children.Add(img, i % 3, i / 3);
//}
//else
//{
// grid.Children.Add(button, i % 5, i / 5);
//}
}
this.Content = new ScrollView
{
Orientation = ScrollOrientation.Vertical,
Content = grid
};
So here I added 12 images to test my code. The page is looking good in portrait-orientation and is having a lot of space between columns if the device is in landscape-orientation.
I'm also trying to use dependency injection to retrieve the information. The DependencyService is doing his job, but I don't have any success retrieving the orientation of the device...
In xamarin.forms, you can get notification from android part by using MessageCenter.
1.In Shared Project
public partial class MyPage : ContentPage
{
public MyPage ()
{
InitializeComponent ();
Stack = new StackLayout
{
Orientation = StackOrientation.Vertical,
};
Stack.Children.Add (new Button { Text = "one" });
Stack.Children.Add (new Button { Text = "two" });
Stack.Children.Add (new Button { Text = "three" });
Content = Stack;
MessagingCenter.Subscribe<MyPage> (this, "Vertical", (sender) =>
{
this.Stack.Orientation = StackOrientation.Vertical;
this.ForceLayout();
});
MessagingCenter.Subscribe<MyPage> (this, "Horizontal", (sender) =>
{
this.Stack.Orientation = StackOrientation.Horizontal;
this.ForceLayout();
});
}
public StackLayout Stack;
}
2.In Android Project
[Activity (Label = "XamFormOrientation.Android.Android", MainLauncher = true, ConfigurationChanges = global::Android.Content.PM.ConfigChanges.Orientation | global::Android.Content.PM.ConfigChanges.ScreenSize)]
public class MainActivity : AndroidActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
Xamarin.Forms.Forms.Init (this, bundle);
SetPage (App.GetMainPage ());
}
public override void OnConfigurationChanged (global::Android.Content.Res.Configuration newConfig)
{
base.OnConfigurationChanged (newConfig);
if (newConfig.Orientation == global::Android.Content.Res.Orientation.Portrait) {
MessagingCenter.Send<MyPage> (null, "Vertical");
} else if (newConfig.Orientation == global::Android.Content.Res.Orientation.Landscape) {
MessagingCenter.Send<MyPage> (null, "Horizontal");
}
}
}
I solved a similar problem and find it on great post which maybe helpfull for you (see hyperlink below).
In shortcut : Find out orientation by
Page.Width < Page.Height
and use this information in constructor of ContentPage (or other) when creating page
http://www.sellsbrothers.com/Posts/Details/13740
I am trying to load a picture that is fetched on-demand from Google's Static Maps based against a (UK) Post Code.
Lets say I have a client and the clients has an address. One of the properties of client is PostCode. I have a form that loads clients. I feed the client ID to this form's constructor and then use LINQ 2 SQL to load all sorts of information including an address.
private void LoadBranchDetails() {
Text_Update_BI_Name.Text = Branch.BranchNumber;
Text_Update_BI_Manager.Text = String.Format("{0} {1}", Branch.PharmacyManager.FirstName, Branch.PharmacyManager.LastName);
DropDownList_Update_BI_Coordinator.SelectedValue = Branch.CoordinatorID;
DropDownList_Update_BI_ComputerSystem.SelectedValue = Branch.ComputerSystemID;
Text_Update_BI_Phone.Text = Branch.PhoneNumber;
Text_Update_BI_Fax.Text = Branch.FaxNumber;
Address BranchAddress = Branch.Contact.Addresses.FirstOrDefault();
Text_Update_AI_House.Text = BranchAddress.HouseNumber;
Text_Update_AI_Street.Text = BranchAddress.Street;
Text_Update_AI_Area.Text = BranchAddress.Area;
Text_Update_AI_Post.Text = BranchAddress.PostCode;
DropDownList_Update_AI_City.SelectedValue = BranchAddress.City.OID;
MaskedText_Update_OI_NoPharmacist.Value = Branch.NumberOfPharmacists;
MaskedText_Update_OI_NoDispensers.Value = Branch.NumberOfDispensers;
MaskedText_Update_OI_NoMonFri.Value = Branch.NumberOfItemsMondayToFriday;
MaskedText_Update_OI_NoSat.Value = Branch.NumberOfItemsSaturday;
MaskedText_Update_OI_NoSun.Value = Branch.NumberOfItemsSunday;
MaskedText_Update_OI_NoAddicts.Value = Branch.NumberOfAddicts;
MaskedText_Update_OI_NoSupervised.Value = Branch.Supervised;
MaskedText_Update_OI_NoUnsupervised.Value = Branch.Unsupervised;
Check_Update_OI_ConfRoom.Checked = Branch.ConsultationRoom;
try {
PictureGoogleMaps.Image = GoogleAddressInfo.FetchMapInfo(Text_Update_AI_Post.Text).GoogleStaticMap;
} catch (Exception) {
PictureGoogleMaps.Image = Resources.DefaultGoogleMap;
}
}
The line that loads the image into the PictureGoogleMaps causes a hang in UI as the ".GoogleStaticMap" property generates the Google static image when called.
Upon searching the internet, i found this helpful example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Declare a list of URLs and their respective picture boxes
var items = new Dictionary<string, PictureBox>
{
{ "http://www.google.com/logos/spring09.gif", new PictureBox() { Top = 0, Width = 300, Height = 80 } },
{ "http://www.google.com/logos/stpatricks_d4gwinner_eo09.gif", new PictureBox() { Top = 100, Width = 300, Height = 80 } },
{ "http://www.google.com/logos/schiaparelli09.gif", new PictureBox() { Top = 200, Width = 300, Height = 80 } },
{ "http://www.google.com/logos/drseuss09.gif", new PictureBox() { Top = 300, Width = 300, Height = 80 } },
{ "http://www.google.com/logos/valentines09.gif", new PictureBox() { Top = 400, Width = 300, Height = 80 } },
{ "http://www.google.com/logos/unix1234567890.gif", new PictureBox() { Top = 500, Width = 300, Height = 80 } },
{ "http://www.google.com/logos/charlesdarwin_09.gif", new PictureBox() { Top = 600, Width = 300, Height = 80 } },
};
foreach (var item in items)
{
var worker = new BackgroundWorker();
worker.DoWork += (o, e) =>
{
// This function will be run on a background thread
// spawned from the thread pool.
using (var client = new WebClient())
{
var pair = (KeyValuePair<string, PictureBox>)e.Argument;
e.Result = new KeyValuePair<PictureBox, byte[]>(pair.Value, client.DownloadData(pair.Key));
}
};
worker.RunWorkerCompleted += (o, e) =>
{
// This function will be run on the main GUI thread
var pair = (KeyValuePair<PictureBox, byte[]>)e.Result;
using (var stream = new MemoryStream(pair.Value))
{
pair.Key.Image = new Bitmap(stream);
}
Controls.Add(pair.Key);
};
worker.RunWorkerAsync(item);
}
}
}
Now I just need to figure out how to remove the for loop and use this in my scenario. Any ideas?
The sample code comes from this link.
Thanks.
public partial class Form1 : Form
{
private BackgroundWorker imageLoader;
public Form1()
{
InitializeComponent();
this.imageLoader = new BackgroundWorker();
this.imageLoader.DoWork += HandleOnImageLoaderDoWork;
this.imageLoader.RunWorkerCompleted += HandleImageLoaderOnRunWorkerCompleted;
this.LoadUserDetails(1);
}
private void LoadUserDetails(Int32 userID)
{
this.imageLoader.RunWorkerAsync(userID.ToString());
// get the user details
// populate the UI controls with the data....
}
private void HandleImageLoaderOnRunWorkerCompleted(Object sender, RunWorkerCompletedEventArgs e)
{
this.pictureBox1.Image = (Image)e.Result;
}
private void HandleOnImageLoaderDoWork(Object sender, DoWorkEventArgs e)
{
// simulate a web request for an image;
Thread.Sleep(3000);
Image image = Image.FromFile(#"test.jpg");
e.Result = image;
}
}
Also make sure that you show some UI notification that a background operation is in process...something like a initial image (loading.gif) in the PictureBox.
Is it that hard to remove the foreach loop? You only need to load a single picture so remove the foreach loop and pass the url of the picture and the target picturebox to the backgroundworker.