Access a image control in another page, class windows phone - c#

Can access an control (image) from another class in C#, XAML?
For example: In class A (image) is collapsed/hidden, when check if image is collapsed/hidden in class B, i want to be visible/enabled, it's possible?
Thanks!

You can use the PhoneApplicationService to do it.
For example:
Suppose you navigated from class A to class B.
In class B, before you navigate back to class A, set
PhoneApplicationService.Current.State["showImage"] = true;
In class A, implement OnNavigatedTo to handle it:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (PhoneApplicationService.Current.State.ContainsKey("showImage"))
{
bool showImage = (bool)PhoneApplicationService.Current.State["showImage"];
if (showImage)
{
this.YourImage.Visibility = System.Windows.Visibility.Visible;
}
else
{
this.YourImage.Visibility = System.Windows.Visibility.Collapsed;
}
PhoneApplicationService.Current.State.Remove("showImage");
}
}
EDIT:
For multiple images, you can try the following approach:
In class B, instead of passing a bool to the PhoneApplicationService, pass a Dictionary of bools, each one representing the state of a image:
var showImage = new Dictionary<int, bool>();
showImage[1] = true;
showImage[2] = false;
showImage[3] = true;
PhoneApplicationService.Current.State["showImage"] = showImage;
In class A, create a dictionary for your images:
private Dictionary<int, Image> _images = new Dictionary<int, Image>();
Then in its constructor, fill the dictionaries with your Images:
InitializeComponent();
_images[1] = YourImage1;
_images[2] = YourImage2;
_images[3] = YourImage3;
In class A's OnNavigatedTo, do:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (PhoneApplicationService.Current.State.ContainsKey("showImage"))
{
var showImage = PhoneApplicationService.Current.State["showImage"] as Dictionary<int, bool>;
if (showImage != null)
{
foreach (var key in showImage.Keys)
{
if (_images.ContainsKey(key))
{
if (showImage[key])
{
_images[key].Visibility = System.Windows.Visibility.Visible;
}
else
{
_images[key].Visibility = System.Windows.Visibility.Collapsed;
}
}
}
}
}
}
If you prefer, you can change the key of the dictionaries for a more representative string.
Hope it helps! :)

Related

How to keep variable through an event?

I have a method to populate a combobox with some strings. At the end of the method I assign to the SelectedIndexChanged event. Here's how that method looks
public ComboBox PopulateComboBox()
{
Worksheet sheetWithTemplateNames = _iReader.GetWorksheetByName("Templates");
int lastRowOfTemplates = _iReader.GetLastRow(sheetWithTemplateNames);
var templateNames = _iHandler.GetTemplateNames(sheetWithTemplateNames, lastRowOfTemplates);
foreach (var template in templateNames)
{
Box.Items.Add(template);
}
Box.SelectedIndexChanged += Box_SelectedIndexChanged;
return Box;
}
and it works as I want to. My problem is that I need to use this templateNames list in the actual event and that's causing trouble. Here's how my event looks like now but ain't functioning.
private void Box_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cmb = (ComboBox)sender;
var chosenObject = cmb.SelectedIndex;
MessageBox.Show(templateNames[chosenObject]);
}
but my list is now empty. It's instantiated in the constructor so I'd assume it'd keep it's state but that isn't the situation. Here's the top of the class
public class TemplateListCombobox
{
public ComboBox Box { get; set; }
private IDataReader _iReader;
private IDataHandler _iHandler;
private List<string> templateNames;
public TemplateListCombobox()
{
Box = new ComboBox();
_iReader = new DataReader();
_iHandler = new DataHandler();
templateNames = new List<string>();
}
}
so how could I possibly keep the state of my list through the event?
UPDATE:
MY class that calls this:
public static class GroupBoxHolder
{
private static GroupBox _thisGroupBox;
public static GroupBox GetGroupBox()
{
PopulateGroupBox();
return _thisGroupBox;
}
public static void PopulateGroupBox()
{
_thisGroupBox = new GroupBox();
TemplateListCombobox combo = new TemplateListCombobox();
ComboBox box = combo.GetComboBox();
_thisGroupBox.Controls.Add(box);
ConfigureGroupBox();
}
public static void ConfigureGroupBox()
{
_thisGroupBox.Location = new Point { X = 75, Y = 15 };
_thisGroupBox.Height = 150;
_thisGroupBox.Width = 400;
}
}
and my updated class
public class TemplateListCombobox
{
private ComboBox _box;
private readonly IDataReader _iReader;
private readonly IDataHandler _iHandler;
private readonly Worksheet _sheetWithTemplateNames;
public TemplateListCombobox()
{
_box = new ComboBox();
_iReader = new DataReader();
_iHandler = new DataHandler();
_sheetWithTemplateNames = _iReader.GetWorksheetByName("Templates");
PopulateComboBox();
}
public void PopulateComboBox()
{
int lastRowOfTemplates = _iReader.GetLastRow(_sheetWithTemplateNames);
var templateNames = _iHandler.GetTemplateNames(_sheetWithTemplateNames, lastRowOfTemplates);
foreach (var template in templateNames)
{
_box.Items.Add(template);
}
_box.SelectedIndexChanged += Box_SelectedIndexChanged;
}
public ComboBox GetComboBox()
{
return _box;
}
private void Box_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cmb = (ComboBox)sender;
var chosenObject = cmb.SelectedItem.ToString();
var firstRowForTemplate = _iReader.GetFirstRowForTemplate(_sheetWithTemplateNames, chosenObject.ToString());
var attributes = _iReader.GetTemplateAttributes(_sheetWithTemplateNames, chosenObject, firstRowForTemplate);
}
}
A. Two lists?
var templateNames = creates a new local variable.
Do you want to set a member field instead? If so, remove var.
B. Read from comobox
Since the combo box contains the names read directly from it.
The flow of the code is something like the following:
var templateNames = _iHandler.GetTemplateNames(sheetWithTemplateNames, lastRowOfTemplates);
foreach (var template in templateNames)
{
Box.Items.Add(template);
}
... time passes
var chosenObject = cmb.SelectedIndex;
MessageBox.Show(templateNames[chosenObject]);
The combobox contains all the information you need. (You could use SelectedItem).
Note on two sources.
Since you're not clearing the combobox's items in the populate method, if it was called twice the combobox would gain new elements. That's not great but more importantly templateNames[chosenObject] would not work anymore because the combobox and the list would be out of sync.
In addition to the var templateNames mistake that doesn't cause the problem, you don't call PopulateComboBox in the code you provide, so the list is empty...
I don't understand why this method returns the Box since there is no parameter and it is a member field that you access directly in the code.
You only need to assign the event in the constructor, not each time you call the populate method that you need to call somewhere.
You should improve your class design because there is several clumsiness. For example, what is TemplateListCombobox without parent and how do you intend to use it? How are initialized _iReader and _iHandler? Do you need to keep templateNames? And so on...

How can I pair objects to radio buttons?

I'm working on a small form app, and I have "paired" my radio buttons with lists in a common class. The purpose of this was to turn on/off the corresponding list
public class myType
{
public RadioButton button { get; set; }
public ListBox list { get; set; }
}
I proceed to create these pairs through a for loop inside an array
for (int i = 0; i < broj_botuna; i++)
{
theArray[i] = new myType();
}
I use a common event handler for all the radio buttons:
private void test_CheckedChanged(object sender, EventArgs e)
{
var xx = sender as RadioButton;
//do stuff
positionInArray = Array.IndexOf(theArray, xx);
}
except that the last line of code "xx" should be of type "myType" and not "radioButton" that I managed to retrieve.
So could anyone tell me how do I get the reference from "radioButton" to "myType"? Or is there a better alternative?
You can use Array.FindIndex like:
var positionInArray = Array.FindIndex(theArray, b => b.button == xx);
You could create some constructs that allow you to easily associate your properties to the parent object if you wanted to.
This approach would allow you to always reference your parent type provided that you added a bit more code in your get's and set's.
static void Main()
{
myType item = new myType();
var button = new Button();
myType.button = button;
var list = new ListBox();
myType.list = list;
item = list.GetParent();
bool isSameButton = button == item.button;
bool isSameList = list == item.list;
Assert.IsTrue(isSameButton);
Assert.IsTrue(isSameList);
}
public class myType
{
private RadioButton _button;
public RadioButton button
{
get { return _button; }
set {
value.AssociateParent(this);
_button = value;
}
}
private ListBox _list;
public ListBox list
{
get { return _list; }
set {
value.AssociateParent(this);
_list= value;
}
}
}
public static class Extensions
{
private static Dictionary<object, object> Items { get; set; }
static Extensions()
{
Items = new Dictionary<object, object>();
}
public static void AssociateParent(this object child, object parent)
{
Items[child] = parent;
}
public static object GetParent(this object child)
{
if (Items.ContainsKey(child)) return Items[child];
return null;
}
}

How to create user control for displaying collection of other user controls in WinForms?

I need to create a user control MyTypeListControl to display collection of objects of type MyType using a user controls MyTypeDisplayControl instance for each of those objects.
So that I could
add instance of MyTypeListControl to my WinForm, then
load collection of MyType and
assign it to MyTypeListControl's DataSource.
In the result it should generate and show appropriate count of MyTypeDisplayControl instances in MyTypeListControl's instance.
In case if I needed to show list of properties - equivalent would be DataGrid with specific fields from MyType assigned to specific DataGrid's columns, but I want to view each MyType item as a user control - with more power for visual representation and functionality than DataGrid provides for it's rows.
Is that even possible?
I found this SO resource how to create My collection type, but this is only small part of the problem solution...
It is quite easy (if you know how) and doesn't take so much effort as you might think in the first place (at least for a simple implementation that handles collection of less then 100 items).
So at first lets create a MyType:
public class MyType
{
public static MyType Empty = new MyType(String.Empty, DateTime.MinValue);
public MyType(string myName, DateTime myBirthday)
{
MyName = myName;
MyBirthday = myBirthday;
}
public DateTime MyBirthday { get; private set; }
public string MyName { get; private set; }
}
At next we need a MyTypeControl:
public partial class MyTypeControl : UserControl
{
private MyType _MyType;
private Label labelBirthday;
private Label labelName;
private Label labelSeparator;
public MyTypeControl()
{
InitializeComponent();
}
public event EventHandler MyTypeChanged;
public MyType MyType
{
get { return _MyType; }
set
{
if (_MyType == value)
return;
_MyType = value ?? MyType.Empty;
OnMyTypeChanged(EventArgs.Empty);
}
}
protected virtual void OnMyTypeChanged(EventArgs eventArgs)
{
UpdateVisualization();
RaiseEvent(MyTypeChanged, eventArgs);
}
protected void UpdateVisualization()
{
SuspendLayout();
labelName.Text = _MyType.MyName;
labelBirthday.Text = _MyType.MyBirthday.ToString("F");
labelBirthday.Visible = _MyType.MyBirthday != DateTime.MinValue;
ResumeLayout();
}
private void InitializeComponent()
{
labelName = new Label();
labelBirthday = new Label();
labelSeparator = new Label();
SuspendLayout();
labelName.Dock = DockStyle.Top;
labelName.Location = new Point(0, 0);
labelName.TextAlign = ContentAlignment.MiddleCenter;
labelBirthday.Dock = DockStyle.Top;
labelBirthday.TextAlign = ContentAlignment.MiddleCenter;
labelSeparator.BorderStyle = BorderStyle.Fixed3D;
labelSeparator.Dock = DockStyle.Top;
labelSeparator.Size = new Size(150, 2);
Controls.Add(labelSeparator);
Controls.Add(labelBirthday);
Controls.Add(labelName);
MinimumSize = new Size(0, 48);
Name = "MyTypeControl";
Size = new Size(150, 48);
ResumeLayout(false);
}
private void RaiseEvent(EventHandler eventHandler, EventArgs eventArgs)
{
var temp = eventHandler;
if (temp != null)
temp(this, eventArgs);
}
}
Then comes our magically list control:
public class MyTypeListControl : UserControl
{
private ObservableCollection<MyType> _Items;
public MyTypeListControl()
{
AutoScroll = true;
_Items = new ObservableCollection<MyType>();
_Items.CollectionChanged += OnItemsCollectionChanged;
}
public Collection<MyType> Items
{
get { return _Items; }
}
private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateVisualization();
}
private void UpdateVisualization()
{
SuspendLayout();
Controls.Clear();
foreach (var item in _Items)
{
var control = new MyTypeControl { MyType = item, Dock = DockStyle.Top };
Controls.Add(control);
Controls.SetChildIndex(control, 0);
}
ResumeLayout();
}
}
And now simply create the list control in your form or parent control and fill it with some meaningful values:
myTypeListControl.Items.Add(new MyType("Adam", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 40))));
myTypeListControl.Items.Add(new MyType("Eva", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 38))));

C# - Accessing a list of Objects from one class to another

I am having this very strange problem where i am creating a list of some objects in one class then trying to access it in another class but it's coming empty in other class:
My first class where i am populating the list:
namespace dragdrop
{
struct BR
{
private string var;
public string Var
{
get { return var; }
set { var = value; }
}
private string equalsTo;
public string EqualsTo
{
get { return equalsTo; }
set { equalsTo = value; }
}
private string output;
public string Output
{
get { return output; }
set { output = value; }
}
private string els;
public string Els
{
get { return els; }
set { els = value; }
}
private string elsOutput;
public string ElsOutput
{
get { return elsOutput; }
set { elsOutput = value; }
}
}
public partial class Form1 : Form
{
//******************
private List<BR> list = new List<BR>(); //This is the list!
//******************
internal List<BR> List
{
get { return list; }
set { list = value; }
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] vars = new string[] { "Name", "Gender", "Age", "Address", "email" };
comboBox1.DataSource = vars;
}
private void button1_Click(object sender, EventArgs e)
{
BR b = new BR();
b.Var = comboBox1.SelectedItem.ToString();
b.EqualsTo = textBox1.Text;
b.Output = textBox2.Text;
list.Add(b);
//*****************
textBox1.Text = List.Count.ToString(); //This gives the correct count value!
//*****************
//this.Close();
}
}
}
I am accessing it in second class like:
namespace dragdrop
{
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
Form1 form = new Form1();
List<BR> l = form.List; ;
//*******************
MessageBox.Show(form.List.Count.ToString()); //This strangely gives count 0!
//*******************
}
}
}
I have even tried making everything public in first class but no matter what i do, im always getting empty list in second class.
The is no relation what-so-ever between Form1 and Ribbon1, how can one then access an instance of the other?
With this:
Form1 form = new Form1(); // new instance of Form1
List<BR> l = form.List; ; // of course the list is empty in a new instance!
you can never access values from another instance of Form1.
Since I have no idea how your classes are connected I cannot give you more advice than have a look at this good overview of OO-relationships. You have to connect them somehow for it to work, I would very much recommend composition // aggregation (same thing, different schools).
All i needed to do was make the list a static member in class one, that solved the issue of having different value when i tried to create a new instance of Form1 in Ribbon1 class.
private static List<BR> list = new List<BR>();

Filtering a ListBox

I have a ListBox named lsbEntities. I want to filter it's items based on some selected radio button.
The code below is kind of pseudo, is their a better approach?
private List<string> _listBoxItemsToFilter;
private Thread tFilterEntityList;
enum EntityType
{
Vehicle,
Facility
}
private void FilterEntityList(EntityType entityType)
{
_listBoxItemsToFilter = new List<string>();
Dictionary<string,string> entitiesAndClassTypes;
List<string> listBoxItems = new List<string>();
for(int i = 0; i < lsbEntities.Count; i++)
{
//object listItem = lsbEntities.Items[i];
listBoxItems.Add(lsbEntities[i].ToString());
}
// get associated types
entityClassTypes = _controlFacade.GetClassTypes(listBoxItems);
foreach (KeyValuePair<string,string>
entityAndClass in entitiesAndClassTypes)
{
classType = entityAndClass.Value;
if(classType != entityType)
{
_listBoxItemsToFilter.Add(entityAndClass.Key);
}
}
RemoveFilterFromEntityListBox();
AddFilterToEntityListBox();
}
private void AddFilterToEntityListBox()
{
// DELEGATE NEEDED TO MODIFY LISTBOX FROM THREAD
foreach(string listBoxItem in _listBoxItemsToFilter)
{
if(lsbEntities.Contains(listBoxItem)
{
// REMOVE WITH DELEGATE
}
}
}
private void RemoveFilterFromEntityListBox()
{
// DELEGATE NEEDED TO MODIFY LISTBOX FROM THREAD
if(_listBoxItemsToFilter != null)
{
foreach(string listBoxItem in _listBoxItemsToFilter)
{
if(!lsbEntities.Contains(listBoxItem)
{
// REMOVE WITH DELEGATE
}
}
}
}
// EXAMPLE CALL WHEN CLICKING RADIO-BUTTON
private void rbVehicles_CheckedChanged(object sender, EventArgs e)
{
switch (rbVehicles.Checked)
{
case (true):
{
object entityType = (object)EntityType.Vehicle;
tFilterEntityList = new Thread(FilterEntityList(entityType));
tFilterEntityList.IsBackground = true;
tFilterEntityList.Start();
//FilterEntityList(EntityType.Vehicle);
break;
}
}
}
I have only included an example of selecting to filter everything but VehicleS. The same approach would be used for the Facility class, where the thread would be re-instantiated.
Here is a simple example showing one way to filter items in a ListBox. This could be improved by using a ListView or DataGridView in VirtualMode. It is very unclear to me what you are trying to do, so if this is not helpful I will remove it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public class Form1 : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
List<Entity> items = new List<Entity>()
{
new Entity(EntityType.Vehicle, "Car"),
new Entity(EntityType.Vehicle, "Aeroplane"),
new Entity(EntityType.Vehicle, "Truck"),
new Entity(EntityType.Vehicle, "Bus"),
new Entity(EntityType.Facility, "Garage"),
new Entity(EntityType.Facility, "House"),
new Entity(EntityType.Facility, "Shack"),
};
ListBox listBox;
ComboBox comboBox;
public Form1()
{
Text = "Filtering Demo";
ClientSize = new Size(500, 320);
Controls.Add(listBox = new ListBox
{
Location = new Point(10, 10),
Size = new Size(200, 300),
});
Controls.Add(comboBox = new ComboBox
{
Location = new Point(230, 10),
DropDownStyle = ComboBoxStyle.DropDownList,
Items = { "All", EntityType.Vehicle, EntityType.Facility },
SelectedIndex = 0,
});
comboBox.SelectedIndexChanged += UpdateFilter;
UpdateFilter(comboBox, EventArgs.Empty);
}
void UpdateFilter(object sender, EventArgs e)
{
var filtered = items.Where((i) => comboBox.SelectedItem is string || (EntityType)comboBox.SelectedItem == i.EntityType);
listBox.DataSource = new BindingSource(filtered, "");
}
}
enum EntityType { Vehicle, Facility, }
class Entity : INotifyPropertyChanged
{
public string Name { get; private set; }
public EntityType EntityType { get; private set; }
public Entity(EntityType entityType, string name) { EntityType = entityType; Name = name; }
public override string ToString() { return Name ?? String.Empty; }
// Implementing INotifyPropertyChanged to eliminate (caught) BindingSource exceptions
public event PropertyChangedEventHandler PropertyChanged;
}

Categories